diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md index 5bedd0a0..bc618c15 100644 --- a/problems/0001.两数之和.md +++ b/problems/0001.两数之和.md @@ -352,5 +352,86 @@ List twoSum(List nums, int target) { } ``` +C: +```c + + +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ + +// leetcode 支持 ut_hash 函式庫 + + typedef struct { + int key; + int value; + UT_hash_handle hh; // make this structure hashable + } map; + +map* hashMap = NULL; + + void hashMapAdd(int key, int value){ + map* s; + // key already in the hash? + HASH_FIND_INT(hashMap, &key, s); + if(s == NULL){ + s = (map*)malloc(sizeof(map)); + s -> key = key; + HASH_ADD_INT(hashMap, key, s); + } + s -> value = value; + } + +map* hashMapFind(int key){ + map* s; + // *s: output pointer + HASH_FIND_INT(hashMap, &key, s); + return s; + } + + void hashMapCleanup(){ + map* cur, *tmp; + HASH_ITER(hh, hashMap, cur, tmp){ + HASH_DEL(hashMap, cur); + free(cur); + } + } + + void hashPrint(){ + map* s; + for(s = hashMap; s != NULL; s=(map*)(s -> hh.next)){ + printf("key %d, value %d\n", s -> key, s -> value); + } + } + + +int* twoSum(int* nums, int numsSize, int target, int* returnSize){ + int i, *ans; + // hash find result + map* hashMapRes; + hashMap = NULL; + ans = malloc(sizeof(int) * 2); + + for(i = 0; i < numsSize; i++){ + // key 代表 nums[i] 的值,value 代表所在 index; + hashMapAdd(nums[i], i); + } + + hashPrint(); + + for(i = 0; i < numsSize; i++){ + hashMapRes = hashMapFind(target - nums[i]); + if(hashMapRes && hashMapRes -> value != i){ + ans[0] = i; + ans[1] = hashMapRes -> value ; + *returnSize = 2; + return ans; + } + } + + hashMapCleanup(); + return NULL; +} +``` -----------------------
diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index 00caeea0..f84e334e 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -75,7 +75,12 @@ public: fast = fast->next; slow = slow->next; } - slow->next = slow->next->next; + slow->next = slow->next->next; + + // ListNode *tmp = slow->next; C++释放内存的逻辑 + // slow->next = tmp->next; + // delete nth; + return dummyHead->next; } }; @@ -87,30 +92,27 @@ public: java: ```java -class Solution { - public ListNode removeNthFromEnd(ListNode head, int n) { - ListNode dummy = new ListNode(-1); - dummy.next = head; +public ListNode removeNthFromEnd(ListNode head, int n){ + ListNode dummyNode = new ListNode(0); + dummyNode.next = head; - ListNode slow = dummy; - ListNode fast = dummy; - while (n-- > 0) { - fast = fast.next; - } - // 记住 待删除节点slow 的上一节点 - ListNode prev = null; - while (fast != null) { - prev = slow; - slow = slow.next; - fast = fast.next; - } - // 上一节点的next指针绕过 待删除节点slow 直接指向slow的下一节点 - prev.next = slow.next; - // 释放 待删除节点slow 的next指针, 这句删掉也能AC - slow.next = null; + ListNode fastIndex = dummyNode; + ListNode slowIndex = dummyNode; - return dummy.next; + //只要快慢指针相差 n 个结点即可 + for (int i = 0; i < n ; i++){ + fastIndex = fastIndex.next; } + + while (fastIndex.next != null){ + fastIndex = fastIndex.next; + slowIndex = slowIndex.next; + } + + //此时 slowIndex 的位置就是待删除元素的前一个位置。 + //具体情况可自己画一个链表长度为 3 的图来模拟代码来理解 + slowIndex.next = slowIndex.next.next; + return dummyNode.next; } ``` @@ -341,5 +343,28 @@ object Solution { } } ``` + +Rust: +```rust +impl Solution { + pub fn remove_nth_from_end(head: Option>, mut n: i32) -> Option> { + let mut dummy_head = Box::new(ListNode::new(0)); + dummy_head.next = head; + let mut fast = &dummy_head.clone(); + let mut slow = &mut dummy_head; + while n > 0 { + fast = fast.next.as_ref().unwrap(); + n -= 1; + } + while fast.next.is_some() { + fast = fast.next.as_ref().unwrap(); + slow = slow.next.as_mut().unwrap(); + } + slow.next = slow.next.as_mut().unwrap().next.take(); + dummy_head.next + } +} +``` + -----------------------
diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index 10337a7f..d65d0bca 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -380,5 +380,51 @@ function swapPairs($head) } ``` +Rust: + +```rust +// 虚拟头节点 +impl Solution { + pub fn swap_pairs(head: Option>) -> Option> { + let mut dummy_head = Box::new(ListNode::new(0)); + dummy_head.next = head; + let mut cur = dummy_head.as_mut(); + while let Some(mut node) = cur.next.take() { + if let Some(mut next) = node.next.take() { + node.next = next.next.take(); + next.next = Some(node); + cur.next = Some(next); + cur = cur.next.as_mut().unwrap().next.as_mut().unwrap(); + } else { + cur.next = Some(node); + cur = cur.next.as_mut().unwrap(); + } + } + dummy_head.next + } +} +``` + +```rust +// 递归 +impl Solution { + pub fn swap_pairs(head: Option>) -> Option> { + if head == None || head.as_ref().unwrap().next == None { + return head; + } + + let mut node = head.unwrap(); + + if let Some(mut next) = node.next.take() { + node.next = Solution::swap_pairs(next.next); + next.next = Some(node); + Some(next) + } else { + Some(node) + } + } +} +``` + -----------------------
diff --git a/problems/0035.搜索插入位置.md b/problems/0035.搜索插入位置.md index 4b17bec6..cd2c88eb 100644 --- a/problems/0035.搜索插入位置.md +++ b/problems/0035.搜索插入位置.md @@ -429,7 +429,57 @@ function searchInsert($nums, $target) return $r + 1; } ``` - +### C +```c +//版本一 [left, right]左闭右闭区间 +int searchInsert(int* nums, int numsSize, int target){ + //左闭右开区间 [0 , numsSize-1] + int left =0; + int mid =0; + int right = numsSize - 1; + while(left <= right){//左闭右闭区间 所以可以 left == right + mid = left + (right - left) / 2; + if(target < nums[mid]){ + //target 在左区间 [left, mid - 1]中,原区间包含mid,右区间边界可以向左内缩 + right = mid -1; + }else if( target > nums[mid]){ + //target 在右区间 [mid + 1, right]中,原区间包含mid,左区间边界可以向右内缩 + left = mid + 1; + }else { + // nums[mid] == target ,顺利找到target,直接返回mid + return mid; + } + } + //数组中未找到target元素 + //target在数组所有元素之后,[left, right]是右闭区间,需要返回 right +1 + return right + 1; +} +``` +```c +//版本二 [left, right]左闭右开区间 +int searchInsert(int* nums, int numsSize, int target){ + //左闭右开区间 [0 , numsSize) + int left =0; + int mid =0; + int right = numsSize; + while(left < right){//左闭右闭区间 所以 left < right + mid = left + (right - left) / 2; + if(target < nums[mid]){ + //target 在左区间 [left, mid)中,原区间没有包含mid,右区间边界不能内缩 + right = mid ; + }else if( target > nums[mid]){ + // target 在右区间 [mid+1, right)中,原区间包含mid,左区间边界可以向右内缩 + left = mid + 1; + }else { + // nums[mid] == target ,顺利找到target,直接返回mid + return mid; + } + } + //数组中未找到target元素 + //target在数组所有元素之后,[left, right)是右开区间, return right即可 + return right; +} +``` -----------------------
diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md index 13142c99..59e30df5 100644 --- a/problems/0045.跳跃游戏II.md +++ b/problems/0045.跳跃游戏II.md @@ -214,7 +214,26 @@ class Solution: return ans ``` +```python +# 贪心版本二 +class Solution: + def jump(self, nums: List[int]) -> int: + if len(nums) == 1: + return 0 + curDistance, nextDistance = 0, 0 + step = 0 + for i in range(len(nums)-1): + nextDistance = max(nextDistance, nums[i]+i) + if i == curDistance: + curDistance = nextDistance + step += 1 + return step +``` + + + ### Go + ```Go func jump(nums []int) int { dp := make([]int, len(nums)) @@ -240,7 +259,71 @@ func min(a, b int) int { } ``` +```go +// 贪心版本一 +func jump(nums []int) int { + n := len(nums) + if n == 1 { + return 0 + } + cur, next := 0, 0 + step := 0 + for i := 0; i < n; i++ { + next = max(nums[i]+i, next) + if i == cur { + if cur != n-1 { + step++ + cur = next + if cur >= n-1 { + return step + } + } else { + return step + } + } + } + return step +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + +```go +// 贪心版本二 +func jump(nums []int) int { + n := len(nums) + if n == 1 { + return 0 + } + cur, next := 0, 0 + step := 0 + for i := 0; i < n-1; i++ { + next = max(nums[i]+i, next) + if i == cur { + cur = next + step++ + } + } + return step +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + + + ### Javascript + ```Javascript var jump = function(nums) { let curIndex = 0 diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md index 394117ee..f2bcedcc 100644 --- a/problems/0055.跳跃游戏.md +++ b/problems/0055.跳跃游戏.md @@ -139,7 +139,31 @@ func canJUmp(nums []int) bool { } ``` +```go +// 贪心 +func canJump(nums []int) bool { + cover := 0 + n := len(nums)-1 + for i := 0; i <= cover; i++ { // 每次与覆盖值比较 + cover = max(i+nums[i], cover) //每走一步都将 cover 更新为最大值 + if cover >= n { + return true + } + } + return false +} +func max(a, b int ) int { + if a > b { + return a + } + return b +} +``` + + + ### Javascript + ```Javascript var canJump = function(nums) { if(nums.length === 1) return true diff --git a/problems/0072.编辑距离.md b/problems/0072.编辑距离.md index e40461de..df57b5b8 100644 --- a/problems/0072.编辑距离.md +++ b/problems/0072.编辑距离.md @@ -362,7 +362,33 @@ function minDistance(word1: string, word2: string): number { }; ``` +C: +```c +int min(int num1, int num2, int num3) { + return num1 > num2 ? (num2 > num3 ? num3 : num2) : (num1 > num3 ? num3 : num1); +} + +int minDistance(char * word1, char * word2){ + int dp[strlen(word1)+1][strlen(word2)+1]; + dp[0][0] = 0; + for (int i = 1; i <= strlen(word1); i++) dp[i][0] = i; + for (int i = 1; i <= strlen(word2); i++) dp[0][i] = i; + + for (int i = 1; i <= strlen(word1); i++) { + for (int j = 1; j <= strlen(word2); j++) { + if (word1[i-1] == word2[j-1]) { + dp[i][j] = dp[i-1][j-1]; + } + else { + dp[i][j] = min(dp[i-1][j-1], dp[i][j-1], dp[i-1][j]) + 1; + } + } + } + return dp[strlen(word1)][strlen(word2)]; +} +``` + -----------------------
diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index 9e7e3bd0..81c0f94a 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -367,6 +367,39 @@ function subsetsWithDup(nums: number[]): number[][] { }; ``` +set去重版本: +```typescript +// 使用set去重版本 +function subsetsWithDup(nums: number[]): number[][] { + const result: number[][] = []; + const path: number[] = []; + // 去重之前先排序 + nums.sort((a, b) => a - b); + function backTracking(startIndex: number) { + // 收集结果 + result.push([...path]) + // 此处不返回也可以因为,每次递归都会使startIndex + 1,当这个数大到nums.length的时候就不会进入递归了。 + if (startIndex === nums.length) { + return + } + // 定义每一个树层的set集合 + const set: Set = new Set() + for (let i = startIndex; i < nums.length; i++) { + // 去重 + if (set.has(nums[i])) { + continue + } + set.add(nums[i]) + path.push(nums[i]) + backTracking(i + 1) + // 回溯 + path.pop() + } + } + backTracking(0) + return result +}; +``` ### Rust ```Rust diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md index 2bcc9c5c..a7c206af 100644 --- a/problems/0104.二叉树的最大深度.md +++ b/problems/0104.二叉树的最大深度.md @@ -313,6 +313,31 @@ class solution { } ``` +```java +class Solution { + /** + * 递归法(求深度法) + */ + //定义最大深度 + int maxnum = 0; + + public int maxDepth(TreeNode root) { + ans(root,0); + return maxnum; + } + + //递归求解最大深度 + void ans(TreeNode tr,int tmp){ + if(tr==null) return; + tmp++; + maxnum = maxnum 0 { + n := q.Len() + for i := 0; i < n; i++ { + node := q.Remove(q.Front()).(*Node) + for j := range node.Children { + q.PushBack(node.Children[j]) + } + } + depth++ + } + return depth +} +``` ## javascript diff --git a/problems/0129.求根到叶子节点数字之和.md b/problems/0129.求根到叶子节点数字之和.md index 859df39e..bd5107a2 100644 --- a/problems/0129.求根到叶子节点数字之和.md +++ b/problems/0129.求根到叶子节点数字之和.md @@ -320,8 +320,11 @@ TypeScript: ```typescript function sumNumbers(root: TreeNode | null): number { if (root === null) return 0; + // 记录最终结果 let resTotal: number = 0; + // 记录路径中遇到的节点值 const route: number[] = []; + // 递归初始值 route.push(root.val); recur(root, route); return resTotal; @@ -342,6 +345,7 @@ function sumNumbers(root: TreeNode | null): number { }; } function listToSum(nums: number[]): number { + // 数组求和 return Number(nums.join('')); } }; diff --git a/problems/0139.单词拆分.md b/problems/0139.单词拆分.md index d60fd46c..5226502a 100644 --- a/problems/0139.单词拆分.md +++ b/problems/0139.单词拆分.md @@ -344,6 +344,21 @@ func wordBreak(s string,wordDict []string) bool { } return dp[len(s)] } +// 转化为 求装满背包s的前几位字符的方式有几种 +func wordBreak(s string, wordDict []string) bool { + // 装满背包s的前几位字符的方式有几种 + dp := make([]int, len(s)+1) + dp[0] = 1 + for i := 0; i <= len(s); i++ { // 背包 + for j := 0; j < len(wordDict); j++ { // 物品 + if i >= len(wordDict[j]) && wordDict[j] == s[i-len(wordDict[j]):i] { + dp[i] += dp[i-len(wordDict[j])] + } + } + } + + return dp[len(s)] > 0 +} ``` Javascript: diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 306af14b..802b5e3d 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -89,7 +89,12 @@ C++代码如下: class Solution { public: int evalRPN(vector& tokens) { +<<<<<<< HEAD stack st; +======= + // 力扣修改了后台测试数据,需要用longlong + stack st; +>>>>>>> 28f3b52a82e3cc650290fb02030a53900e122f43 for (int i = 0; i < tokens.size(); i++) { if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") { long long num1 = st.top(); @@ -104,11 +109,13 @@ public: st.push(stoll(tokens[i])); } } + int result = st.top(); st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事) return result; } }; + ``` ## 题外话 diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index a848d6a3..be35c2f2 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -360,6 +360,75 @@ class Solution { } ``` +```java +/* + * 解法四:时间复杂度 O(n) + * 参考卡哥 c++ 代码的三步骤:先移除多余空格,再将整个字符串反转,最后把单词逐个反转 + * 有别于解法一 :没有用 StringBuilder 实现,而是对 String 的 char[] 数组操作来实现以上三个步骤 + */ +class Solution { + //用 char[] 来实现 String 的 removeExtraSpaces,reverse 操作 + public String reverseWords(String s) { + char[] chars = s.toCharArray(); + //1.去除首尾以及中间多余空格 + chars = removeExtraSpaces(chars); + //2.整个字符串反转 + reverse(chars, 0, chars.length - 1); + //3.单词反转 + reverseEachWord(chars); + return new String(chars); + } + + //1.用 快慢指针 去除首尾以及中间多余空格,可参考数组元素移除的题解 + public char[] removeExtraSpaces(char[] chars) { + int slow = 0; + for (int fast = 0; fast < chars.length; fast++) { + //先用 fast 移除所有空格 + if (chars[fast] != ' ') { + //在用 slow 加空格。 除第一个单词外,单词末尾要加空格 + if (slow != 0) + chars[slow++] = ' '; + //fast 遇到空格或遍历到字符串末尾,就证明遍历完一个单词了 + while (fast < chars.length && chars[fast] != ' ') + chars[slow++] = chars[fast++]; + } + } + //相当于 c++ 里的 resize() + char[] newChars = new char[slow]; + System.arraycopy(chars, 0, newChars, 0, slow); + return newChars; + } + + //双指针实现指定范围内字符串反转,可参考字符串反转题解 + public void reverse(char[] chars, int left, int right) { + if (right >= chars.length) { + System.out.println("set a wrong right"); + return; + } + while (left < right) { + chars[left] ^= chars[right]; + chars[right] ^= chars[left]; + chars[left] ^= chars[right]; + left++; + right--; + } + } + + //3.单词反转 + public void reverseEachWord(char[] chars) { + int start = 0; + //end <= s.length() 这里的 = ,是为了让 end 永远指向单词末尾后一个位置,这样 reverse 的实参更好设置 + for (int end = 0; end <= chars.length; end++) { + // end 每次到单词末尾后的空格或串尾,开始反转单词 + if (end == chars.length || chars[end] == ' ') { + reverse(chars, start, end - 1); + start = end + 1; + } + } + } +} +``` + python: ```Python diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index e97befee..009b4469 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -588,5 +588,45 @@ object Solution { } ``` + +Rust: +双指针法: + +```rust +impl Solution { + pub fn reverse_list(head: Option>) -> Option> { + let mut cur = head; + let mut pre = None; + while let Some(mut node) = cur.take() { + cur = node.next; + node.next = pre; + pre = Some(node); + } + pre + } +} +``` + +递归法: + +```rust +impl Solution { + pub fn reverse_list(head: Option>) -> Option> { + fn rev( + mut head: Option>, + mut pre: Option>, + ) -> Option> { + if let Some(mut node) = head.take() { + let cur = node.next; + node.next = pre; + pre = Some(node); + return rev(cur, pre); + } + pre + } + rev(head, None) + } +} +``` -----------------------
diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md index 2a018736..0bcd31e5 100644 --- a/problems/0209.长度最小的子数组.md +++ b/problems/0209.长度最小的子数组.md @@ -181,23 +181,23 @@ class Solution: index += 1 return 0 if res==float("inf") else res ``` -```python3 -#滑动窗口 +```python +# 滑动窗口 class Solution: def minSubArrayLen(self, target: int, nums: List[int]) -> int: - if nums is None or len(nums)==0: + if nums is None or len(nums) == 0: return 0 - lenf=len(nums)+1 - total=0 - i=j=0 - while (j=target): - lenf=min(lenf,j-i) - total=total-nums[i] - i+=1 - if lenf==len(nums)+1: + lenf = len(nums) + 1 + total = 0 + i = j = 0 + while (j < len(nums)): + total = total + nums[j] + j += 1 + while (total >= target): + lenf = min(lenf, j - i) + total = total - nums[i] + i += 1 + if lenf == len(nums) + 1: return 0 else: return lenf diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md index dc037f0a..eecc4dc1 100644 --- a/problems/0222.完全二叉树的节点个数.md +++ b/problems/0222.完全二叉树的节点个数.md @@ -437,6 +437,33 @@ func countNodes(root *TreeNode) int { } ``` +迭代法 + +```go +func countNodes(root *TreeNode) int { + if root == nil { + return 0 + } + q := list.New() + q.PushBack(root) + res := 0 + for q.Len() > 0 { + n := q.Len() + for i := 0; i < n; i++ { + node := q.Remove(q.Front()).(*TreeNode) + if node.Left != nil { + q.PushBack(node.Left) + } + if node.Right != nil { + q.PushBack(node.Right) + } + res++ + } + } + return res +} +``` + ## JavaScript: diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md index fb2851f1..4412a819 100644 --- a/problems/0225.用队列实现栈.md +++ b/problems/0225.用队列实现栈.md @@ -292,6 +292,40 @@ class MyStack { } ``` +优化,使用一个 Queue 实现 +```java +class MyStack { + + Queue queue; + + public MyStack() { + queue = new LinkedList<>(); + } + + //每 offer 一个数(A)进来,都重新排列,把这个数(A)放到队列的队首 + public void push(int x) { + queue.offer(x); + int size = queue.size(); + //移动除了 A 的其它数 + while (size-- > 1) + queue.offer(queue.poll()); + } + + public int pop() { + return queue.poll(); + } + + public int top() { + return queue.peek(); + } + + public boolean empty() { + return queue.isEmpty(); + } +} + +``` + Python: ```python diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md index f9e8e7f1..93a4c2d3 100644 --- a/problems/0455.分发饼干.md +++ b/problems/0455.分发饼干.md @@ -274,6 +274,7 @@ function findContentChildren(g: number[], s: number[]): number { ### C ```c +///小餅乾先餵飽小胃口的 int cmp(int* a, int* b) { return *a - *b; } @@ -296,6 +297,33 @@ int findContentChildren(int* g, int gSize, int* s, int sSize){ } ``` +```c +///大餅乾先餵飽大胃口的 +int cmp(int* a, int* b) { + return *a - *b; +} + +int findContentChildren(int* g, int gSize, int* s, int sSize){ + if(sSize == 0) + return 0; + + //将两个数组排序为升序 + qsort(g, gSize, sizeof(int), cmp); + qsort(s, sSize, sizeof(int), cmp); + + int count = 0; + int start = sSize - 1; + + for(int i = gSize - 1; i >= 0; i--) { + if(start >= 0 && s[start] >= g[i] ) { + start--; + count++; + } + } + return count; +} +``` + ### Scala ```scala diff --git a/problems/0583.两个字符串的删除操作.md b/problems/0583.两个字符串的删除操作.md index fd80853e..c33f7f58 100644 --- a/problems/0583.两个字符串的删除操作.md +++ b/problems/0583.两个字符串的删除操作.md @@ -47,6 +47,8 @@ dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word 那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1}); +因为dp[i - 1][j - 1] + 1等于 dp[i - 1][j] 或 dp[i][j - 1],所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1); + 3. dp数组如何初始化 @@ -90,7 +92,7 @@ public: if (word1[i - 1] == word2[j - 1]) { dp[i][j] = dp[i - 1][j - 1]; } else { - dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1}); + dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1); } } } diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index 83e57fec..1f7e6cbf 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -1240,6 +1240,94 @@ class MyLinkedList() { } ``` +Rust: + +```rust +#[derive(Debug)] +pub struct MyLinkedList { + pub val: i32, + pub next: Option>, +} + +impl MyLinkedList { + fn new() -> Self { + // 增加头节点 + MyLinkedList { val: 0, next: None } + } + + fn get(&self, index: i32) -> i32 { + if index < 0 { + return -1; + } + let mut i = 0; + let mut cur = &self.next; + while let Some(node) = cur { + if i == index { + return node.val; + } + i += 1; + cur = &node.next; + } + -1 + } + + fn add_at_head(&mut self, val: i32) { + let new_node = Box::new(MyLinkedList { + val, + next: self.next.take(), + }); + self.next = Some(new_node); + } + + fn add_at_tail(&mut self, val: i32) { + let new_node = Box::new(MyLinkedList { val, next: None }); + let mut last_node = &mut self.next; + while let Some(node) = last_node { + last_node = &mut node.next; + } + *last_node = Some(new_node); + } + + fn add_at_index(&mut self, index: i32, val: i32) { + if index <= 0 { + self.add_at_head(val); + } else { + let mut i = 0; + let mut cur = &mut self.next; + while let Some(node) = cur { + if i + 1 == index { + let new_node = Box::new(MyLinkedList { + val, + next: node.next.take(), + }); + node.next = Some(new_node); + break; + } + i += 1; + cur = &mut node.next; + } + } + } + + fn delete_at_index(&mut self, index: i32) { + if index < 0 { + return; + } + + let mut i = 0; + let mut cur = self; + while let Some(node) = cur.next.take() { + if i == index { + cur.next = node.next; + break; + } + i += 1; + cur.next = Some(node); + cur = cur.next.as_mut().unwrap(); + } + } +} +``` -----------------------
diff --git a/problems/1049.最后一块石头的重量II.md b/problems/1049.最后一块石头的重量II.md index b6a674aa..728ae83e 100644 --- a/problems/1049.最后一块石头的重量II.md +++ b/problems/1049.最后一块石头的重量II.md @@ -43,7 +43,7 @@ 是不是感觉和昨天讲解的[416. 分割等和子集](https://programmercarl.com/0416.分割等和子集.html)非常像了。 -本题物品的重量为store[i],物品的价值也为store[i]。 +本题物品的重量为stones[i],物品的价值也为stones[i]。 对应着01背包里的物品重量weight[i]和 物品价值value[i]。 diff --git a/problems/剑指Offer05.替换空格.md b/problems/剑指Offer05.替换空格.md index e1ccc458..7a2712ef 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -156,20 +156,20 @@ char* replaceSpace(char* s){ Java: ```Java //使用一个新的对象,复制 str,复制的过程对其判断,是空格则替换,否则直接复制,类似于数组复制 -public static String replaceSpace(StringBuffer str) { - if (str == null) { +public static String replaceSpace(String s) { + if (s == null) { return null; } - //选用 StringBuilder 单线程使用,比较快,选不选都行 + //选用 StringBuilder 单线程使用,比较快,选不选都行 StringBuilder sb = new StringBuilder(); - //使用 sb 逐个复制 str ,碰到空格则替换,否则直接复制 - for (int i = 0; i < str.length(); i++) { - //str.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型 - //if (" ".equals(String.valueOf(str.charAt(i)))){ + //使用 sb 逐个复制 s ,碰到空格则替换,否则直接复制 + for (int i = 0; i < s.length(); i++) { + //s.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型 + //if (" ".equals(String.valueOf(s.charAt(i)))){} if (s.charAt(i) == ' ') { sb.append("%20"); } else { - sb.append(str.charAt(i)); + sb.append(s.charAt(i)); } } return sb.toString(); diff --git a/problems/剑指Offer58-II.左旋转字符串.md b/problems/剑指Offer58-II.左旋转字符串.md index bf5d3f90..b14c26cc 100644 --- a/problems/剑指Offer58-II.左旋转字符串.md +++ b/problems/剑指Offer58-II.左旋转字符串.md @@ -115,6 +115,29 @@ class Solution { } ``` +```java +//解法二:空间复杂度:O(1)。用原始数组来进行反转操作 +//思路为:先整个字符串反转,再反转前面的,最后反转后面 n 个 +class Solution { + public String reverseLeftWords(String s, int n) { + char[] chars = s.toCharArray(); + reverse(chars, 0, chars.length - 1); + reverse(chars, 0, chars.length - 1 - n); + reverse(chars, chars.length - n, chars.length - 1); + return new String(chars); + } + + public void reverse(char[] chars, int left, int right) { + while (left < right) { + chars[left] ^= chars[right]; + chars[right] ^= chars[left]; + chars[left] ^= chars[right]; + left++; + right--; + } + } +``` + python: ```python diff --git a/problems/双指针总结.md b/problems/双指针总结.md index 06752cac..5abcec53 100644 --- a/problems/双指针总结.md +++ b/problems/双指针总结.md @@ -42,7 +42,7 @@ for (int i = 0; i < array.size(); i++) { **其实很多数组(字符串)填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。** -那么在[字符串:花式反转还不够!](https://programmercarl.com/0151.翻转字符串里的单词.html)中,我们使用双指针法,用O(n)的时间复杂度完成字符串删除类的操作,因为题目要产出冗余空格。 +那么在[字符串:花式反转还不够!](https://programmercarl.com/0151.翻转字符串里的单词.html)中,我们使用双指针法,用O(n)的时间复杂度完成字符串删除类的操作,因为题目要删除冗余空格。 **在删除冗余空格的过程中,如果不注意代码效率,很容易写成了O(n^2)的时间复杂度。其实使用双指针法O(n)就可以搞定。** diff --git a/problems/链表理论基础.md b/problems/链表理论基础.md index 8378f7f2..cdd861fd 100644 --- a/problems/链表理论基础.md +++ b/problems/链表理论基础.md @@ -218,6 +218,22 @@ class ListNode(_x: Int = 0, _next: ListNode = null) { } ``` +Rust: +```rust +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct ListNode { + pub val: T, + pub next: Option>>, +} + +impl ListNode { + #[inline] + fn new(val: T, node: Option>>) -> Self { + ListNode { next: node, val } + } +} +``` + -----------------------