This commit is contained in:
toly
2023-11-26 09:04:44 +08:00
parent 6e8d926693
commit 2ceed8b9b5
20 changed files with 597 additions and 18 deletions

View File

@@ -0,0 +1,39 @@
void main(){
/// 打印 1->9->9->4
ListNode listNode = ListNode(1, ListNode(9, ListNode(9,ListNode(4))));
print(listNode);
ListNode? result = listNode.reverseList(listNode);
print(result);
}
class ListNode {
int val;
ListNode? next;
ListNode([this.val = 0, this.next]);
@override
String toString(){
ListNode? cur = this;
String result = "";
while( cur!=null){
result = result +cur.val.toString();
cur = cur.next;
if(cur!=null){
result +='->';
}
}
return result;
}
ListNode? reverseList(ListNode? head) {
if (head == null || head.next == null) return head;
ListNode? pre = reverseList(head.next);
head.next?.next = head;
head.next = null;
return pre;
}
}

158
test/parser/path_utils.dart Normal file
View File

@@ -0,0 +1,158 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
final RegExp _parameterRegExp = RegExp(r':(\w+)(\((?:\\.|[^\\()])+\))?');
/// Converts a [pattern] such as `/user/:id` into [RegExp].
///
/// The path parameters can be specified by prefixing them with `:`. The
/// `parameters` are used for storing path parameter names.
///
///
/// For example:
///
/// `pattern` = `/user/:id/book/:bookId`
///
/// The `parameters` would contain `['id', 'bookId']` as a result of calling
/// this method.
///
/// To extract the path parameter values from a [RegExpMatch], pass the
/// [RegExpMatch] into [extractPathParameters] with the `parameters` that are
/// used for generating the [RegExp].
RegExp patternToRegExp(String pattern, List<String> parameters) {
final StringBuffer buffer = StringBuffer('^');
int start = 0;
for (final RegExpMatch match in _parameterRegExp.allMatches(pattern)) {
if (match.start > start) {
buffer.write(RegExp.escape(pattern.substring(start, match.start)));
}
final String name = match[1]!;
final String? optionalPattern = match[2];
final String regex = optionalPattern != null
? _escapeGroup(optionalPattern, name)
: '(?<$name>[^/]+)';
buffer.write(regex);
parameters.add(name);
start = match.end;
}
if (start < pattern.length) {
buffer.write(RegExp.escape(pattern.substring(start)));
}
if (!pattern.endsWith('/')) {
buffer.write(r'(?=/|$)');
}
return RegExp(buffer.toString(), caseSensitive: false);
}
String _escapeGroup(String group, [String? name]) {
final String escapedGroup = group.replaceFirstMapped(
RegExp(r'[:=!]'), (Match match) => '\\${match[0]}');
if (name != null) {
return '(?<$name>$escapedGroup)';
}
return escapedGroup;
}
/// Reconstructs the full path from a [pattern] and path parameters.
///
/// This is useful for restoring the original path from a [RegExpMatch].
///
/// For example, A path matched a [RegExp] returned from [patternToRegExp] and
/// produced a [RegExpMatch]. To reconstruct the path from the match, one
/// can follow these steps:
///
/// 1. Get the `pathParameters` by calling [extractPathParameters] with the
/// [RegExpMatch] and the parameters used for generating the [RegExp].
/// 2. Call [patternToPath] with the `pathParameters` from the first step and
/// the original `pattern` used for generating the [RegExp].
String patternToPath(String pattern, Map<String, String> pathParameters) {
final StringBuffer buffer = StringBuffer();
int start = 0;
for (final RegExpMatch match in _parameterRegExp.allMatches(pattern)) {
if (match.start > start) {
buffer.write(pattern.substring(start, match.start));
}
final String name = match[1]!;
buffer.write(pathParameters[name]);
start = match.end;
}
if (start < pattern.length) {
buffer.write(pattern.substring(start));
}
return buffer.toString();
}
/// Extracts arguments from the `match` and maps them by parameter name.
///
/// The [parameters] should originate from the call to [patternToRegExp] that
/// creates the [RegExp].
Map<String, String> extractPathParameters(
List<String> parameters, RegExpMatch match) {
return <String, String>{
for (int i = 0; i < parameters.length; ++i)
parameters[i]: match.namedGroup(parameters[i])!
};
}
/// Concatenates two paths.
///
/// e.g: pathA = /a, pathB = c/d, concatenatePaths(pathA, pathB) = /a/c/d.
String concatenatePaths(String parentPath, String childPath) {
// at the root, just return the path
if (parentPath.isEmpty) {
assert(childPath.startsWith('/'));
assert(childPath == '/' || !childPath.endsWith('/'));
return childPath;
}
// not at the root, so append the parent path
assert(childPath.isNotEmpty);
assert(!childPath.startsWith('/'));
assert(!childPath.endsWith('/'));
return '${parentPath == '/' ? '' : parentPath}/$childPath';
}
/// Normalizes the location string.
String canonicalUri(String loc) {
String canon = Uri.parse(loc).toString();
canon = canon.endsWith('?') ? canon.substring(0, canon.length - 1) : canon;
// remove trailing slash except for when you shouldn't, e.g.
// /profile/ => /profile
// / => /
// /login?from=/ => login?from=/
canon = canon.endsWith('/') && canon != '/' && !canon.contains('?')
? canon.substring(0, canon.length - 1)
: canon;
// /login/?from=/ => /login?from=/
// /?from=/ => /?from=/
canon = canon.replaceFirst('/?', '?', 1);
return canon;
}
/// Builds an absolute path for the provided route.
// String? fullPathForRoute(
// RouteBase targetRoute, String parentFullpath, List<RouteBase> routes) {
// for (final RouteBase route in routes) {
// final String fullPath = (route is GoRoute)
// ? concatenatePaths(parentFullpath, route.path)
// : parentFullpath;
//
// if (route == targetRoute) {
// return fullPath;
// } else {
// final String? subRoutePath =
// fullPathForRoute(targetRoute, fullPath, route.routes);
// if (subRoutePath != null) {
// return subRoutePath;
// }
// }
// }
// return null;
// }

107
test/parser/uri.dart Normal file
View File

@@ -0,0 +1,107 @@
import 'path_utils.dart';
void main() {
String pattern = '/user/:id/book/:bookId';
String path = '/user/001/book/card';
parserPath();
// List<String> params = [];
// RegExp regExp = patternToRegExp(pattern,params);
//
//
// bool data = regExp.hasMatch(path);
// List<RegExpMatch> matchs = regExp.allMatches(path).toList();
// Map<String,String?> pathParams = {};
// if(matchs.isNotEmpty){
//
// for(int i=0;i<params.length;i++){
// String? value = matchs.first.namedGroup(params[i]);
// pathParams[params[i]] = value;
// }
// }
//
// print(pathParams);
// print(regExp.pattern);
//
// // match.forEach((element) {
// // print(element.namedGroup('id'));
// // });
// // regExp
// print(params);
// String ret = patternToPath(pattern, {
// 'id':'0',
// 'bookId':'card',
// });
// print(regExp);
// print(ret);
}
void parserPath() {
String template = '/user/:id/book/:bookId';
String path = '/user/001/book/card';
List<String> keys = [];
RegExp regExp = patternToRegExp(template,keys);
Map<String, String?> pathParams = {};
RegExpMatch? match = regExp.firstMatch(path);
if (match != null) {
for (int i = 0; i < keys.length; i++) {
String? value = match.namedGroup(keys[i]);
pathParams[keys[i]] = value;
}
}
print(pathParams);
}
final RegExp _parameterRegExp = RegExp(r':(\w+)(\((?:\\.|[^\\()])+\))?');
RegExp patternToRegExp(String pattern, List<String> parameters) {
final StringBuffer buffer = StringBuffer('^');
int start = 0;
for (final RegExpMatch match in _parameterRegExp.allMatches(pattern)) {
if (match.start > start) {
buffer.write(RegExp.escape(pattern.substring(start, match.start)));
}
final String name = match[1]!;
final String? optionalPattern = match[2];
final String regex = optionalPattern != null
? _escapeGroup(optionalPattern, name)
: '(?<$name>[^/]+)';
buffer.write(regex);
parameters.add(name);
start = match.end;
}
if (start < pattern.length) {
buffer.write(RegExp.escape(pattern.substring(start)));
}
if (!pattern.endsWith('/')) {
buffer.write(r'(?=/|$)');
}
return RegExp(buffer.toString(), caseSensitive: false);
}
String _escapeGroup(String group, [String? name]) {
final String escapedGroup = group.replaceFirstMapped(
RegExp(r'[:=!]'), (Match match) => '\\${match[0]}');
if (name != null) {
return '(?<$name>$escapedGroup)';
}
return escapedGroup;
}
void parser() {
String path =
'http://user:pwd@toly1994.com:8080/path1/path2?key1=value1&key2=value2#fragment';
Uri? uri = Uri.tryParse(path);
if (uri == null) return;
print(uri.scheme); // http
print(uri.userInfo); // user:pwd
print(uri.host); // toly1994.com
print(uri.port); // 8080
print(uri.path); // /path1/path2
print(uri.query); // key1=value1&key2=value2
print(uri.fragment); // fragment
}

View File

@@ -0,0 +1,204 @@
/// Dart、Rust 、C++ 、Java
void main() {
ListNode listNode = ListNode(0, ListNode(3, ListNode(2, ListNode(8))));
print(listNode);
// List<int> evens = listNode.getEvenValue();
// print(evens);
// List<int> values = listNode.getValueByStep(2);
// print(values);
// listNode.deleteAt(3);
// ListNode? ret = listNode.deleteFromEnd(2);
// print(ret);
// ListNode? middleNode1 = listNode.middleNode1();
// print(middleNode1);
ListNode? middleNode2 = listNode.middleNode2();
print(middleNode2);
// ListNode? findNode = listNode.find(8);
// if(findNode!=null){
// ListNode? result = listNode.deleteNode(findNode);
// // 0->2->8
// print(result);
// }
}
class ListNode {
int val;
ListNode? next;
ListNode([this.val = 0, this.next]);
//// region [2023.11.20]
@override
String toString() {
ListNode? cur = this;
String result = "";
while (cur != null) {
result = result + cur.val.toString();
cur = cur.next;
if (cur != null) {
result += '->';
}
}
return result;
}
// endregion
//// region [2023.11.21]
/// [2023.11.21] TODO: 完成 find 函数,在链表中查找指定值的首位节点
ListNode? find(int target) {
ListNode? cur = this;
while (cur != null) {
if (cur.val == target) {
return cur;
}
cur = cur.next;
}
return null;
}
/// [2023.11.21]
/// TODO: LeetCode 237 删除指定节点(非尾结点)
void deleteNodeNotLast(ListNode node) {
if (node.next != null) {
node.val = node.next!.val;
node.next = node.next?.next;
}
}
// endregion
//// region [2023.11.22]
/// [2023.11.22]
/// TODO: 完成 size 方法,返回链表长度
int size() {
int i = 0;
ListNode? cur = this;
while (cur != null) {
cur = cur.next;
i++;
}
return i;
}
/// [2023.11.22]
/// TODO: 完成 deleteAt 方法,删除第 index 个节点
void deleteAt(int index) {
if (index == 0) {
ListNode? next = this.next;
this.val = next?.val ?? -1;
this.next = next?.next;
next?.next = null;
return;
}
ListNode? cur = this;
for (int i = 0; i < index - 1; i++) {
cur = cur?.next;
}
ListNode? target = cur?.next;
cur?.next = target?.next;
target?.next = null;
}
/// [2023.11.22]
/// TODO: LeetCode 19 删除链表的倒数第 N 个节点
ListNode? deleteFromEnd(int n) {
ListNode? dummy = ListNode(0, this);
ListNode? first = this;
ListNode? second = dummy;
for (int i = 0; i < n; ++i) {
first = first?.next;
}
while (first != null) {
first = first.next;
second = second?.next;
}
second?.next = second.next?.next;
return dummy.next;
}
ListNode? deleteNode(ListNode node) {
ListNode? cur = this;
if (cur == node) {
cur = cur.next!;
return cur;
}
while (cur != null) {
if (cur.next == node) {
cur.next = cur.next?.next;
return this;
}
cur = cur.next;
}
return this;
}
// endregion
//// region [2023.11.23]
/// [2023.11.23]
/// TODO: 完成 getEvenValue 方法,
/// 返回链表中偶数节点的值列表
List<int> getEvenValue() {
ListNode? cur = this;
List<int> result = [];
while (cur != null) {
result.add(cur.val);
cur = cur.next?.next;
}
return result;
}
/// TODO: 完成 getValueByStep 方法,
/// 返回链表中每隔 step 个节点的值列表
/// 例:
/// 链表: 0->3->2->8->9
/// step=3 : 输出 [0, 8]
/// step=2 : 输出 [0, 2, 9]
List<int> getValueByStep(int step) {
ListNode? cur = this;
List<int> result = [];
while (cur != null) {
result.add(cur.val);
for (int i = 0; i < step; i++) {
cur = cur?.next;
}
}
return result;
}
/// [2023.11.23]
/// TODO: LeetCode 876 链表的中间结点
/// [1,2,3,4,5] -> [3,4,5]
/// [1,2,3,4,5,6] -> [4,5,6]
/// 时间 O(N) 空间 O(N)
ListNode? middleNode1() {
List<ListNode?> nodes = [];
ListNode? cur = this;
while (cur != null) {
nodes.add(cur);
cur = cur.next;
}
return nodes[nodes.length ~/ 2];
}
/// 使用快慢指针 - 一次遍历
ListNode? middleNode2() {
ListNode? slow = this;
ListNode? fast = this;
while (fast != null && fast.next != null) {
slow = slow?.next;
fast = fast.next?.next;
}
return slow;
}
// endregion
}

View File

@@ -0,0 +1,3 @@
class LikedList<T>{
}

View File

@@ -23,7 +23,4 @@ class ListNode {
}
return result;
}
}