diff --git a/README.md b/README.md index df397457..276c8313 100644 --- a/README.md +++ b/README.md @@ -116,10 +116,11 @@ 1. [关于链表,你该了解这些!](./problems/链表理论基础.md) 2. [链表:听说用虚拟头节点会方便很多?](./problems/0203.移除链表元素.md) 3. [链表:一道题目考察了常见的五个操作!](./problems/0707.设计链表.md) -4. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) -5. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) -5. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) -6. [链表:总结篇!](./problems/链表总结篇.md) +4. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) +5. [链表:两两交换链表中的节点](./problems/0024.两两交换链表中的节点.md) +6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) +7. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) +8. [链表:总结篇!](./problems/链表总结篇.md) ## 哈希表 diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md index 6c9d99dd..21f798a9 100644 --- a/problems/0001.两数之和.md +++ b/problems/0001.两数之和.md @@ -106,6 +106,18 @@ public int[] twoSum(int[] nums, int target) { Python: +```python3 +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + hashmap={} + for ind,num in enumerate(nums): + hashmap[num] = ind + for i,num in enumerate(nums): + j = hashmap.get(target - num) + if j is not None and i!=j: + return [i,j] +``` + Go: @@ -122,6 +134,28 @@ func twoSum(nums []int, target int) []int { } ``` +Rust + +```rust +use std::collections::HashMap; + +impl Solution { + pub fn two_sum(nums: Vec, target: i32) -> Vec { + let mut map = HashMap::with_capacity(nums.len()); + + for i in 0..nums.len() { + if let Some(k) = map.get(&(target - nums[i])) { + if *k != i { + return vec![*k as i32, i as i32]; + } + } + map.insert(nums[i], i); + } + panic!("not found") + } +} +``` + diff --git a/problems/0020.有效的括号.md b/problems/0020.有效的括号.md index e8784397..f2d78ade 100644 --- a/problems/0020.有效的括号.md +++ b/problems/0020.有效的括号.md @@ -141,7 +141,20 @@ Java: Python: - +```python3 +class Solution: + def isValid(self, s: str) -> bool: + stack = [] # 保存还未匹配的左括号 + mapping = {")": "(", "]": "[", "}": "{"} + for i in s: + if i in "([{": # 当前是左括号,则入栈 + stack.append(i) + elif stack and stack[-1] == mapping[i]: # 当前是配对的右括号则出栈 + stack.pop() + else: # 不是匹配的右括号或者没有左括号与之匹配,则返回false + return False + return stack == [] # 最后必须正好把左括号匹配完 +``` Go: diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md new file mode 100644 index 00000000..aa284279 --- /dev/null +++ b/problems/0024.两两交换链表中的节点.md @@ -0,0 +1,100 @@ + +

+ + + + +

+

欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ +## 24. 两两交换链表中的节点 + +给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 + +你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + + +![24.两两交换链表中的节点-题意](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9-%E9%A2%98%E6%84%8F.jpg) + +## 思路 + +这道题目正常模拟就可以了。 + +建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。 + +对虚拟头结点的操作,还不熟悉的话,可以看这篇[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)。 + +接下来就是交换相邻两个元素了,**此时一定要画图,不画图,操作多个指针很容易乱,而且要操作的先后顺序** + +初始时,cur指向虚拟头结点,然后进行如下三步: + +![24.两两交换链表中的节点1](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B91.png) + +操作之后,链表如下: + +![24.两两交换链表中的节点2](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B92.png) + +看这个可能就更直观一些了: + + +![24.两两交换链表中的节点3](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B93.png) + +对应的C++代码实现如下: (注释中详细和如上图中的三步做对应) + +```C++ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点 + dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作 + ListNode* cur = dummyHead; + while(cur->next != nullptr && cur->next->next != nullptr) { + ListNode* tmp = cur->next; // 记录临时节点 + ListNode* tmp1 = cur->next->next->next; // 记录临时节点 + + cur->next = cur->next->next; // 步骤一 + cur->next->next = tmp; // 步骤二 + cur->next->next->next = tmp1; // 步骤三 + + cur = cur->next->next; // cur移动两位,准备下一轮交换 + } + return dummyHead->next; + } +}; +``` +* 时间复杂度:$O(n)$ +* 空间复杂度:$O(1)$ + +## 拓展 + +**这里还是说一下,大家不必太在意力扣上执行用时,打败多少多少用户,这个统计不准确的。** + +做题的时候自己能分析出来时间复杂度就可以了,至于力扣上执行用时,大概看一下就行。 + +上面的代码我第一次提交执行用时8ms,打败6.5%的用户,差点吓到我了。 + +心想应该没有更好的方法了吧,也就O(n)的时间复杂度,重复提交几次,这样了: + +![24.两两交换链表中的节点](https://code-thinking.cdn.bcebos.com/pics/24.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.png) + +力扣上的统计如果两份代码是 100ms 和 300ms的耗时,其实是需要注意的。 + +如果一个是 4ms 一个是 12ms,看上去好像是一个打败了80%,一个打败了20%,其实是没有差别的。 只不过是力扣上统计的误差而已。 + + +## 其他语言版本 + + +Java: + + +Python: + +Go: + + +----------------------- +* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) +* B站视频:[代码随想录](https://space.bilibili.com/525438321) +* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) +
diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index 5cfdb68d..144cd5be 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -129,7 +129,19 @@ Python: Go: - +```go +func removeElement(nums []int, val int) int { + length:=len(nums) + res:=0 + for i:=0;i> lists = new ArrayList<>(); + Deque deque = new LinkedList<>(); + public List> combinationSum3(int k, int n) { + int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + backTracking(arr, n, k, 0); + return lists; + } + + public void backTracking(int[] arr, int n, int k, int startIndex) { + //如果 n 小于0,没必要继续本次递归,已经不符合要求了 + if (n < 0) { + return; + } + if (deque.size() == k) { + if (n == 0) { + lists.add(new ArrayList(deque)); + } + return; + } + for (int i = startIndex; i < arr.length - (k - deque.size()) + 1; i++) { + deque.push(arr[i]); + //减去当前元素 + n -= arr[i]; + backTracking(arr, n, k, i + 1); + //恢复n + n += deque.pop(); + } + } +} +``` Python: diff --git a/problems/0040.组合总和II.md b/problems/0040.组合总和II.md index ffcbe212..50898016 100644 --- a/problems/0040.组合总和II.md +++ b/problems/0040.组合总和II.md @@ -255,7 +255,43 @@ public: Java: +```Java +class Solution { + List> lists = new ArrayList<>(); + Deque deque = new LinkedList<>(); + int sum = 0; + public List> combinationSum2(int[] candidates, int target) { + //为了将重复的数字都放到一起,所以先进行排序 + Arrays.sort(candidates); + //加标志数组,用来辅助判断同层节点是否已经遍历 + boolean[] flag = new boolean[candidates.length]; + backTracking(candidates, target, 0, flag); + return lists; + } + + public void backTracking(int[] arr, int target, int index, boolean[] flag) { + if (sum == target) { + lists.add(new ArrayList(deque)); + return; + } + for (int i = index; i < arr.length && arr[i] + sum <= target; i++) { + //出现重复节点,同层的第一个节点已经被访问过,所以直接跳过 + if (i > 0 && arr[i] == arr[i - 1] && !flag[i - 1]) { + continue; + } + flag[i] = true; + sum += arr[i]; + deque.push(arr[i]); + //每个节点仅能选择一次,所以从下一位开始 + backTracking(arr, target, i + 1, flag); + int temp = deque.pop(); + flag[i] = false; + sum -= temp; + } + } +} +``` Python: diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md index 2def83a9..b8e369e6 100644 --- a/problems/0045.跳跃游戏II.md +++ b/problems/0045.跳跃游戏II.md @@ -143,7 +143,36 @@ public: Java: - +```Java +class Solution { + public int jump(int[] nums) { + if (nums == null || nums.length == 0 || nums.length == 1) { + return 0; + } + //记录跳跃的次数 + int count=0; + //当前的覆盖最大区域 + int curDistance = 0; + //最大的覆盖区域 + int maxDistance = 0; + for (int i = 0; i < nums.length; i++) { + //在可覆盖区域内更新最大的覆盖区域 + maxDistance = Math.max(maxDistance,i+nums[i]); + //说明当前一步,再跳一步就到达了末尾 + if (maxDistance>=nums.length-1){ + count++; + break; + } + //走到当前覆盖的最大区域时,更新下一步可达的最大区域 + if (i==curDistance){ + curDistance = maxDistance; + count++; + } + } + return count; + } +} +``` Python: diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md index 5f7b1ac0..05d86785 100644 --- a/problems/0046.全排列.md +++ b/problems/0046.全排列.md @@ -147,7 +147,41 @@ public: Java: +```java +class Solution { + List> result = new ArrayList<>();// 存放符合条件结果的集合 + LinkedList path = new LinkedList<>();// 用来存放符合条件结果 + boolean[] used; + public List> permute(int[] nums) { + if (nums.length == 0){ + return result; + } + used = new boolean[nums.length]; + permuteHelper(nums); + return result; + } + private void permuteHelper(int[] nums){ + if (path.size() == nums.length){ + result.add(new ArrayList<>(path)); + return; + } + for (int i = 0; i < nums.length; i++){ + // if (path.contains(nums[i])){ + // continue; + // } + if (used[i]){ + continue; + } + used[i] = true; + path.add(nums[i]); + permuteHelper(nums); + path.removeLast(); + used[i] = false; + } + } +} +``` Python: diff --git a/problems/0053.最大子序和.md b/problems/0053.最大子序和.md index b8a9d748..b8b11a57 100644 --- a/problems/0053.最大子序和.md +++ b/problems/0053.最大子序和.md @@ -139,7 +139,25 @@ public: Java: - +```java +class Solution { + public int maxSubArray(int[] nums) { + if (nums.length == 1){ + return nums[0]; + } + int sum = Integer.MIN_VALUE; + int count = 0; + for (int i = 0; i < nums.length; i++){ + count += nums[i]; + sum = Math.max(sum, count); // 取区间累计的最大值(相当于不断确定最大子序终止位置) + if (count <= 0){ + count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和 + } + } + return sum; + } +} +``` Python: diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md index 0cad1fa7..179ac246 100644 --- a/problems/0055.跳跃游戏.md +++ b/problems/0055.跳跃游戏.md @@ -86,7 +86,25 @@ public: Java: - +```Java +class Solution { + public boolean canJump(int[] nums) { + if (nums.length == 1) { + return true; + } + //覆盖范围 + int coverRange = nums[0]; + //在覆盖范围内更新最大的覆盖范围 + for (int i = 0; i <= coverRange; i++) { + coverRange = Math.max(coverRange, i + nums[i]); + if (coverRange >= nums.length - 1) { + return true; + } + } + return false; + } +} +``` Python: diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 3dfb5216..f31766e0 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -340,6 +340,33 @@ public: Java: +```java +class Solution { + List> result = new ArrayList<>(); + LinkedList path = new LinkedList<>(); + public List> combine(int n, int k) { + combineHelper(n, k, 1); + return result; + } + + /** + * 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex + * @param startIndex 用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。 + */ + private void combineHelper(int n, int k, int startIndex){ + //终止条件 + if (path.size() == k){ + result.add(new ArrayList<>(path)); + return; + } + for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){ + path.add(i); + combineHelper(n, k, i + 1); + path.removeLast(); + } + } +} +``` Python: diff --git a/problems/0078.子集.md b/problems/0078.子集.md index 8c68843d..77854133 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -177,7 +177,33 @@ public: Java: +```java +class Solution { + List> result = new ArrayList<>();// 存放符合条件结果的集合 + LinkedList path = new LinkedList<>();// 用来存放符合条件结果 + public List> subsets(int[] nums) { + if (nums.length == 0){ + result.add(new ArrayList<>()); + return result; + } + Arrays.sort(nums); + subsetsHelper(nums, 0); + return result; + } + private void subsetsHelper(int[] nums, int startIndex){ + result.add(new ArrayList<>(path));//「遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合」。 + if (startIndex >= nums.length){ //终止条件可不加 + return; + } + for (int i = startIndex; i < nums.length; i++){ + path.add(nums[i]); + subsetsHelper(nums, i + 1); + path.removeLast(); + } + } +} +``` Python: diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index cc5fd571..47db79f7 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -172,7 +172,40 @@ if (i > startIndex && nums[i] == nums[i - 1] ) { Java: - +```java +class Solution { + List> result = new ArrayList<>();// 存放符合条件结果的集合 + LinkedList path = new LinkedList<>();// 用来存放符合条件结果 + boolean[] used; + public List> subsetsWithDup(int[] nums) { + if (nums.length == 0){ + result.add(path); + return result; + } + Arrays.sort(nums); + used = new boolean[nums.length]; + subsetsWithDupHelper(nums, 0); + return result; + } + + private void subsetsWithDupHelper(int[] nums, int startIndex){ + result.add(new ArrayList<>(path)); + if (startIndex >= nums.length){ + return; + } + for (int i = startIndex; i < nums.length; i++){ + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]){ + continue; + } + path.add(nums[i]); + used[i] = true; + subsetsWithDupHelper(nums, i + 1); + path.removeLast(); + used[i] = false; + } + } +} +``` Python: diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index cfbe09f3..be2e9dca 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -419,6 +419,37 @@ public: Java: +``` Java + + +class Solution { + public List> resList=new ArrayList>(); + public List> levelOrder(TreeNode root) { + checkFun01(root,0); + + return resList; + } + + //递归方式 + public void checkFun01(TreeNode node,Integer deep){ + if(node==null) return; + deep++; + + if(resList.size() item=new ArrayList(); + resList.add(item); + } + resList.get(deep-1).add(node.val); + + + checkFun01(node.left,deep); + checkFun01(node.right,deep); + } + + +``` + Python: diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 40df1e7a..718a2f5b 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -312,6 +312,74 @@ Python: Go: +JavaScript: + +0112.路径总和 + +```javascript +/** + * @param {TreeNode} root + * @param {number} targetSum + * @return {boolean} + */ +let hasPathSum = function (root, targetSum) { + // 递归法 + const traversal = (node, cnt) => { + // 遇到叶子节点,并且计数为0 + if (cnt === 0 && !node.left && !node.right) return true; + // 遇到叶子节点而没有找到合适的边(计数不为0),直接返回 + if (!node.left && !node.right) return false; + + // 左(空节点不遍历).遇到叶子节点返回true,则直接返回true + if (node.left && traversal(node.left, cnt - node.left.val)) return true; + // 右(空节点不遍历) + if (node.right && traversal(node.right, cnt - node.right.val)) return true; + return false; + }; + if (!root) return false; + return traversal(root, targetSum - root.val); + + // 精简代码: + // if (!root) return false; + // if (!root.left && !root.right && targetSum === root.val) return true; + // return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val); +}; +``` + +0113.路径总和-ii + +```javascript +let pathSum = function (root, targetSum) { + // 递归法 + // 要遍历整个树找到所有路径,所以递归函数不需要返回值, 与112不同 + const res = []; + const travelsal = (node, cnt, path) => { + // 遇到了叶子节点且找到了和为sum的路径 + if (cnt === 0 && !node.left && !node.right) { + res.push([...path]); // 不能写res.push(path), 要深拷贝 + return; + } + if (!node.left && !node.right) return; // 遇到叶子节点而没有找到合适的边,直接返回 + // 左 (空节点不遍历) + if (node.left) { + path.push(node.left.val); + travelsal(node.left, cnt - node.left.val, path); // 递归 + path.pop(); // 回溯 + } + // 右 (空节点不遍历) + if (node.right) { + path.push(node.right.val); + travelsal(node.right, cnt - node.right.val, path); // 递归 + path.pop(); // 回溯 + } + return; + }; + if (!root) return res; + travelsal(root, targetSum - root.val, [root.val]); // 把根节点放进路径 + return res; +}; +``` + diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index e6667091..9fca1ee0 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -138,7 +138,63 @@ public: Java: - +```java +/** + * 添加虚节点方式 + * 时间复杂度 O(n) + * 空间复杂度 O(1) + * @param head + * @param val + * @return + */ +public ListNode removeElements(ListNode head, int val) { + if (head == null) { + return head; + } + // 因为删除可能涉及到头节点,所以设置dummy节点,统一操作 + ListNode dummy = new ListNode(-1, head); + ListNode pre = dummy; + ListNode cur = head; + while (cur != null) { + if (cur.val == val) { + pre.next = cur.next; + } else { + pre = cur; + } + cur = cur.next; + } + return dummy.next; +} +/** + * 不添加虚拟节点方式 + * 时间复杂度 O(n) + * 空间复杂度 O(1) + * @param head + * @param val + * @return + */ +public ListNode removeElements(ListNode head, int val) { + while (head != null && head.val == val) { + head = head.next; + } + // 已经为null,提前退出 + if (head == null) { + return head; + } + // 已确定当前head.val != val + ListNode pre = head; + ListNode cur = head.next; + while (cur != null) { + if (cur.val == val) { + pre.next = cur.next; + } else { + pre = cur; + } + cur = cur.next; + } + return head; +} +``` Python: diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index 9c492431..be553c5a 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -91,8 +91,29 @@ Python: Go: - - +```go +func isAnagram(s string, t string) bool { + if len(s)!=len(t){ + return false + } + exists := make(map[byte]int) + for i:=0;i=0&&ok{ + exists[s[i]]=v+1 + }else{ + exists[s[i]]=1 + } + } + for i:=0;i=1&&ok{ + exists[t[i]]=v-1 + }else{ + return false + } + } + return true +} +``` ----------------------- diff --git a/problems/0322.零钱兑换.md b/problems/0322.零钱兑换.md index fbb9c6df..e67695d8 100644 --- a/problems/0322.零钱兑换.md +++ b/problems/0322.零钱兑换.md @@ -181,7 +181,31 @@ public: Java: - +```Java +class Solution { + public int coinChange(int[] coins, int amount) { + int max = Integer.MAX_VALUE; + int[] dp = new int[amount + 1]; + //初始化dp数组为最大值 + for (int j = 0; j < dp.length; j++) { + dp[j] = max; + } + //当金额为0时需要的硬币数目为0 + dp[0] = 0; + for (int i = 0; i < coins.length; i++) { + //正序遍历:完全背包每个硬币可以选择多次 + for (int j = coins[i]; j <= amount; j++) { + //只有dp[j-coins[i]]不是初始最大值时,该位才有选择的必要 + if (dp[j - coins[i]] != max) { + //选择硬币数目最小的情况 + dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1); + } + } + } + return dp[amount] == max ? -1 : dp[amount]; + } +} +``` Python: diff --git a/problems/0377.组合总和Ⅳ.md b/problems/0377.组合总和Ⅳ.md index b0b83718..8f8cfd86 100644 --- a/problems/0377.组合总和Ⅳ.md +++ b/problems/0377.组合总和Ⅳ.md @@ -147,7 +147,23 @@ C++测试用例有超过两个树相加超过int的数据,所以需要在if里 Java: +```Java +class Solution { + public int combinationSum4(int[] nums, int target) { + int[] dp = new int[target + 1]; + dp[0] = 1; + for (int i = 0; i <= target; i++) { + for (int j = 0; j < nums.length; j++) { + if (i >= nums[j]) { + dp[i] += dp[i - nums[j]]; + } + } + } + return dp[target]; + } +} +``` Python: diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index ca9b6061..742bfdc3 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -111,7 +111,31 @@ public: Java: +```Java +class Solution { + public boolean canConstruct(String ransomNote, String magazine) { + //记录杂志字符串出现的次数 + int[] arr = new int[26]; + int temp; + for (int i = 0; i < magazine.length(); i++) { + temp = magazine.charAt(i) - 'a'; + arr[temp]++; + } + for (int i = 0; i < ransomNote.length(); i++) { + temp = ransomNote.charAt(i) - 'a'; + //对于金信中的每一个字符都在数组中查找 + //找到相应位减一,否则找不到返回false + if (arr[temp] > 0) { + arr[temp]--; + } else { + return false; + } + } + return true; + } +} +``` Python: diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index 257c4d7d..789a7fb5 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -185,7 +185,41 @@ public: Java: +```Java +class Solution { + public boolean canPartition(int[] nums) { + int sum = 0; + for (int i : nums) { + sum += i; + } + if ((sum & 1) == 1) { + return false; + } + int length = nums.length; + int target = sum >> 1; + //dp[j]表示前i个元素可以找到相加等于j情况 + boolean[] dp = new boolean[target + 1]; + //对于第一个元素,只有当j=nums[0]时,才恰好填充满 + if (nums[0] <= target) { + dp[nums[0]] = true; + } + for (int i = 1; i < length; i++) { + //j由右往左直到nums[i] + for (int j = target; j >= nums[i]; j--) { + //只有两种情况,要么放,要么不放 + //取其中的TRUE值 + dp[j] = dp[j] || dp[j - nums[i]]; + } + //一旦满足,结束,因为只需要找到一组值即可 + if (dp[target]) { + return dp[target]; + } + } + return dp[target]; + } +} +``` Python: diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index 71dcc1ae..a2ef928b 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -88,7 +88,36 @@ public: Java: - +```Java +class Solution { + public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { + Map map = new HashMap<>(); + int temp; + int res = 0; + //统计两个数组中的元素之和,同时统计出现的次数,放入map + for (int i : nums1) { + for (int j : nums2) { + temp = i + j; + if (map.containsKey(temp)) { + map.put(temp, map.get(temp) + 1); + } else { + map.put(temp, 1); + } + } + } + //统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数 + for (int i : nums3) { + for (int j : nums4) { + temp = i + j; + if (map.containsKey(0 - temp)) { + res += map.get(0 - temp); + } + } + } + return res; + } +} +``` Python: diff --git a/problems/0474.一和零.md b/problems/0474.一和零.md index 7970c38e..4ec5fd4d 100644 --- a/problems/0474.一和零.md +++ b/problems/0474.一和零.md @@ -161,7 +161,33 @@ public: Java: - +```Java +class Solution { + public int findMaxForm(String[] strs, int m, int n) { + //dp[i][j]表示i个0和j个1时的最大子集 + int[][] dp = new int[m + 1][n + 1]; + int oneNum, zeroNum; + for (String str : strs) { + oneNum = 0; + zeroNum = 0; + for (char ch : str.toCharArray()) { + if (ch == '0') { + zeroNum++; + } else { + oneNum++; + } + } + //倒序遍历 + for (int i = m; i >= zeroNum; i--) { + for (int j = n; j >= oneNum; j--) { + dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1); + } + } + } + return dp[m][n]; + } +} +``` Python: diff --git a/problems/0518.零钱兑换II.md b/problems/0518.零钱兑换II.md index 46e52cc0..15c9d7d0 100644 --- a/problems/0518.零钱兑换II.md +++ b/problems/0518.零钱兑换II.md @@ -188,7 +188,22 @@ public: Java: - +```Java +class Solution { + public int change(int amount, int[] coins) { + //递推表达式 + int[] dp = new int[amount + 1]; + //初始化dp数组,表示金额为0时只有一种情况,也就是什么都不装 + dp[0] = 1; + for (int i = 0; i < coins.length; i++) { + for (int j = coins[i]; j <= amount; j++) { + dp[j] += dp[j - coins[i]]; + } + } + return dp[amount]; + } +} +``` Python: diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index 9261e135..bb013d95 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -151,6 +151,22 @@ Java: Python: +```python3 +class Solution: + def search(self, nums: List[int], target: int) -> int: + left, right = 0, len(nums) - 1 + + while left <= right: + middle = (left + right) // 2 + + if nums[middle] < target: + left = middle + 1 + elif nums[middle] > target: + right = middle - 1 + else: + return middle + return -1 +``` Go: diff --git a/problems/0707.设计链表.md b/problems/0707.设计链表.md index f98051c9..93133b55 100644 --- a/problems/0707.设计链表.md +++ b/problems/0707.设计链表.md @@ -157,7 +157,78 @@ private: Java: +```Java +class MyLinkedList { + //size存储链表元素的个数 + int size; + //虚拟头结点 + ListNode head; + //初始化链表 + public MyLinkedList() { + size = 0; + head = new ListNode(0); + } + + //获取第index个节点的数值 + public int get(int index) { + //如果index非法,返回-1 + if (index < 0 || index >= size) { + return -1; + } + ListNode currentNode = head; + //包含一个虚拟头节点,所以查找第 index+1 个节点 + for (int i = 0; i <= index; i++) { + currentNode = currentNode.next; + } + return currentNode.val; + } + + //在链表最前面插入一个节点 + public void addAtHead(int val) { + addAtIndex(0, val); + } + + //在链表的最后插入一个节点 + public void addAtTail(int val) { + addAtIndex(size, val); + } + + // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。 + // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点 + // 如果 index 大于链表的长度,则返回空 + public void addAtIndex(int index, int val) { + if (index > size) { + return; + } + if (index < 0) { + index = 0; + } + size++; + //找到要插入节点的前驱 + ListNode pred = head; + for (int i = 0; i < index; i++) { + pred = pred.next; + } + ListNode toAdd = new ListNode(val); + toAdd.next = pred.next; + pred.next = toAdd; + } + + //删除第index个节点 + public void deleteAtIndex(int index) { + if (index < 0 || index >= size) { + return; + } + size--; + ListNode pred = head; + for (int i = 0; i < index; i++) { + pred = pred.next; + } + pred.next = pred.next.next; + } +} +``` Python: diff --git a/problems/0746.使用最小花费爬楼梯.md b/problems/0746.使用最小花费爬楼梯.md index e87f782c..b8158205 100644 --- a/problems/0746.使用最小花费爬楼梯.md +++ b/problems/0746.使用最小花费爬楼梯.md @@ -203,7 +203,26 @@ public: Java: - +```Java +class Solution { + public int minCostClimbingStairs(int[] cost) { + if (cost == null || cost.length == 0) { + return 0; + } + if (cost.length == 1) { + return cost[0]; + } + int[] dp = new int[cost.length]; + dp[0] = cost[0]; + dp[1] = cost[1]; + for (int i = 2; i < cost.length; i++) { + dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i]; + } + //最后一步,如果是由倒数第二步爬,则最后一步的体力花费可以不用算 + return Math.min(dp[cost.length - 1], dp[cost.length - 2]); + } +} +``` Python: diff --git a/problems/1049.最后一块石头的重量II.md b/problems/1049.最后一块石头的重量II.md index 6f654fac..0ffd6a3e 100644 --- a/problems/1049.最后一块石头的重量II.md +++ b/problems/1049.最后一块石头的重量II.md @@ -155,7 +155,27 @@ public: Java: - +```Java +class Solution { + public int lastStoneWeightII(int[] stones) { + int sum = 0; + for (int i : stones) { + sum += i; + } + int target = sum >> 1; + //初始化dp数组 + int[] dp = new int[target + 1]; + for (int i = 0; i < stones.length; i++) { + //采用倒序 + for (int j = target; j >= stones[i]; j--) { + //两种情况,要么放,要么不放 + dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]); + } + } + return sum - 2 * dp[target]; + } +} +``` Python: diff --git a/problems/二叉树理论基础.md b/problems/二叉树理论基础.md index 726fc7a8..60e65c69 100644 --- a/problems/二叉树理论基础.md +++ b/problems/二叉树理论基础.md @@ -46,7 +46,7 @@ ### 二叉搜索树 -前面介绍的书,都没有数值的,而二叉搜索树是有数值的了,**二叉搜索树是一个有序树**。 +前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,**二叉搜索树是一个有序树**。 * 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; @@ -193,7 +193,13 @@ Python: Go: - +``` +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} +``` diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 6c005191..02d4b060 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -122,6 +122,58 @@ Python: Go: +前序遍历: +``` +func PreorderTraversal(root *TreeNode) (res []int) { + var traversal func(node *TreeNode) + traversal = func(node *TreeNode) { + if node == nil { + return + } + res = append(res,node.Val) + traversal(node.Left) + traversal(node.Right) + } + traversal(root) + return res +} + +``` +中序遍历: + +``` +func InorderTraversal(root *TreeNode) (res []int) { + var traversal func(node *TreeNode) + traversal = func(node *TreeNode) { + if node == nil { + return + } + traversal(node.Left) + res = append(res,node.Val) + traversal(node.Right) + } + traversal(root) + return res +} +``` +后序遍历: + +``` +func PostorderTraversal(root *TreeNode) (res []int) { + var traversal func(node *TreeNode) + traversal = func(node *TreeNode) { + if node == nil { + return + } + traversal(node.Left) + traversal(node.Right) + res = append(res,node.Val) + } + traversal(root) + return res +} +``` +