mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 16:54:50 +08:00
@ -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)
|
||||
|
||||
## 哈希表
|
||||
|
||||
|
@ -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<i32>, target: i32) -> Vec<i32> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
100
problems/0024.两两交换链表中的节点.md
Normal file
100
problems/0024.两两交换链表中的节点.md
Normal file
@ -0,0 +1,100 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||
<a href="https://img-blog.csdnimg.cn/20201210231711160.png"><img src="https://img.shields.io/badge/公众号-代码随想录-brightgreen" alt=""></a>
|
||||
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
|
||||
</p>
|
||||
<p align="center"><strong>欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||
|
||||
## 24. 两两交换链表中的节点
|
||||
|
||||
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
|
||||
|
||||
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
|
||||
|
||||
|
||||

|
||||
|
||||
## 思路
|
||||
|
||||
这道题目正常模拟就可以了。
|
||||
|
||||
建议使用虚拟头结点,这样会方便很多,要不然每次针对头结点(没有前一个指针指向头结点),还要单独处理。
|
||||
|
||||
对虚拟头结点的操作,还不熟悉的话,可以看这篇[链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)。
|
||||
|
||||
接下来就是交换相邻两个元素了,**此时一定要画图,不画图,操作多个指针很容易乱,而且要操作的先后顺序**
|
||||
|
||||
初始时,cur指向虚拟头结点,然后进行如下三步:
|
||||
|
||||

|
||||
|
||||
操作之后,链表如下:
|
||||
|
||||

|
||||
|
||||
看这个可能就更直观一些了:
|
||||
|
||||
|
||||

|
||||
|
||||
对应的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)的时间复杂度,重复提交几次,这样了:
|
||||
|
||||

|
||||
|
||||
力扣上的统计如果两份代码是 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)
|
||||
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
@ -129,7 +129,19 @@ Python:
|
||||
|
||||
|
||||
Go:
|
||||
|
||||
```go
|
||||
func removeElement(nums []int, val int) int {
|
||||
length:=len(nums)
|
||||
res:=0
|
||||
for i:=0;i<length;i++{
|
||||
if nums[i]!=val {
|
||||
nums[res]=nums[i]
|
||||
res++
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
```
|
||||
|
@ -219,7 +219,72 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
```java
|
||||
class Solution {
|
||||
public void solveSudoku(char[][] board) {
|
||||
solveSudokuHelper(board);
|
||||
}
|
||||
|
||||
private boolean solveSudokuHelper(char[][] board){
|
||||
//「一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,
|
||||
// 一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!」
|
||||
for (int i = 0; i < 9; i++){ // 遍历行
|
||||
for (int j = 0; j < 9; j++){ // 遍历列
|
||||
if (board[i][j] != '.'){ // 跳过原始数字
|
||||
continue;
|
||||
}
|
||||
for (char k = '1'; k <= '9'; k++){ // (i, j) 这个位置放k是否合适
|
||||
if (isValidSudoku(i, j, k, board)){
|
||||
board[i][j] = k;
|
||||
if (solveSudokuHelper(board)){ // 如果找到合适一组立刻返回
|
||||
return true;
|
||||
}
|
||||
board[i][j] = '.';
|
||||
}
|
||||
}
|
||||
// 9个数都试完了,都不行,那么就返回false
|
||||
return false;
|
||||
// 因为如果一行一列确定下来了,这里尝试了9个数都不行,说明这个棋盘找不到解决数独问题的解!
|
||||
// 那么会直接返回, 「这也就是为什么没有终止条件也不会永远填不满棋盘而无限递归下去!」
|
||||
}
|
||||
}
|
||||
// 遍历完没有返回false,说明找到了合适棋盘位置了
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断棋盘是否合法有如下三个维度:
|
||||
* 同行是否重复
|
||||
* 同列是否重复
|
||||
* 9宫格里是否重复
|
||||
*/
|
||||
private boolean isValidSudoku(int row, int col, char val, char[][] board){
|
||||
// 同行是否重复
|
||||
for (int i = 0; i < 9; i++){
|
||||
if (board[row][i] == val){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 同列是否重复
|
||||
for (int j = 0; j < 9; j++){
|
||||
if (board[j][col] == val){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 9宫格里是否重复
|
||||
int startRow = (row / 3) * 3;
|
||||
int startCol = (col / 3) * 3;
|
||||
for (int i = startRow; i < startRow + 3; i++){
|
||||
for (int j = startCol; j < startCol + 3; j++){
|
||||
if (board[i][j] == val){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -236,7 +236,39 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
```Java
|
||||
class Solution {
|
||||
List<List<Integer>> lists = new ArrayList<>();
|
||||
Deque<Integer> deque = new LinkedList<>();
|
||||
|
||||
public List<List<Integer>> 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:
|
||||
|
||||
|
@ -255,7 +255,43 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
```Java
|
||||
class Solution {
|
||||
List<List<Integer>> lists = new ArrayList<>();
|
||||
Deque<Integer> deque = new LinkedList<>();
|
||||
int sum = 0;
|
||||
|
||||
public List<List<Integer>> 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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -147,7 +147,41 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
```java
|
||||
class Solution {
|
||||
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
|
||||
LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
|
||||
boolean[] used;
|
||||
public List<List<Integer>> 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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -340,6 +340,33 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
```java
|
||||
class Solution {
|
||||
List<List<Integer>> result = new ArrayList<>();
|
||||
LinkedList<Integer> path = new LinkedList<>();
|
||||
public List<List<Integer>> 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:
|
||||
|
@ -177,7 +177,33 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
```java
|
||||
class Solution {
|
||||
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
|
||||
LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
|
||||
public List<List<Integer>> 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:
|
||||
|
||||
|
@ -172,7 +172,40 @@ if (i > startIndex && nums[i] == nums[i - 1] ) {
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
|
||||
LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
|
||||
boolean[] used;
|
||||
public List<List<Integer>> 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:
|
||||
|
||||
|
@ -419,6 +419,37 @@ public:
|
||||
|
||||
Java:
|
||||
|
||||
``` Java
|
||||
|
||||
|
||||
class Solution {
|
||||
public List<List<Integer>> resList=new ArrayList<List<Integer>>();
|
||||
public List<List<Integer>> levelOrder(TreeNode root) {
|
||||
checkFun01(root,0);
|
||||
|
||||
return resList;
|
||||
}
|
||||
|
||||
//递归方式
|
||||
public void checkFun01(TreeNode node,Integer deep){
|
||||
if(node==null) return;
|
||||
deep++;
|
||||
|
||||
if(resList.size()<deep){
|
||||
//当层级增加时,list的Item也增加,利用list的索引值进行层级界定
|
||||
List<Integer> item=new ArrayList<Integer>();
|
||||
resList.add(item);
|
||||
}
|
||||
resList.get(deep-1).add(node.val);
|
||||
|
||||
|
||||
checkFun01(node.left,deep);
|
||||
checkFun01(node.right,deep);
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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<len(s);i++{
|
||||
if v,ok:=exists[s[i]];v>=0&&ok{
|
||||
exists[s[i]]=v+1
|
||||
}else{
|
||||
exists[s[i]]=1
|
||||
}
|
||||
}
|
||||
for i:=0;i<len(t);i++{
|
||||
if v,ok:=exists[t[i]];v>=1&&ok{
|
||||
exists[t[i]]=v-1
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -88,7 +88,36 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
```Java
|
||||
class Solution {
|
||||
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
|
||||
Map<Integer, Integer> 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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
### 二叉搜索树
|
||||
|
||||
前面介绍的书,都没有数值的,而二叉搜索树是有数值的了,**二叉搜索树是一个有序树**。
|
||||
前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,**二叉搜索树是一个有序树**。
|
||||
|
||||
|
||||
* 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
|
||||
@ -193,7 +193,13 @@ Python:
|
||||
|
||||
|
||||
Go:
|
||||
|
||||
```
|
||||
type TreeNode struct {
|
||||
Val int
|
||||
Left *TreeNode
|
||||
Right *TreeNode
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user