This commit is contained in:
fusunx
2021-05-17 08:35:16 +08:00
37 changed files with 1022 additions and 90 deletions

View File

@ -23,11 +23,17 @@
很多刚开始刷题的同学都有一个困惑面对leetcode上近两千道题目从何刷起。 很多刚开始刷题的同学都有一个困惑面对leetcode上近两千道题目从何刷起。
大家平时刷题感觉效率低,浪费的时间主要在三点:
* 找题
* 找到了不应该现阶段做的题
* 没有全套的优质题解可以参考
其实我之前在知乎上回答过这个问题,回答内容大概是按照如下类型来刷数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心->动态规划->图论->高级数据结构,再从简单刷起,做了几个类型题目之后,再慢慢做中等题目、困难题目。 其实我之前在知乎上回答过这个问题,回答内容大概是按照如下类型来刷数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心->动态规划->图论->高级数据结构,再从简单刷起,做了几个类型题目之后,再慢慢做中等题目、困难题目。
但我能设身处地的感受到:即使有这样一个整体规划,对于一位初学者甚至算法老手寻找合适自己的题目也是很困难,时间成本很高,而且题目还不一定就是经典题目。 但我能设身处地的感受到:即使有这样一个整体规划,对于一位初学者甚至算法老手寻找合适自己的题目也是很困难,时间成本很高,而且题目还不一定就是经典题目。
对于刷题,我们都是想用最短的时间把经典题目都做一,这样效率才是最高的! 对于刷题,我们都是想用最短的时间**按照循序渐进的难度顺序把经典题目都做一遍**,这样效率才是最高的!
所以我整理了leetcode刷题攻略一个超级详细的刷题顺序**每道题目都是我精心筛选,都是经典题目高频面试题**,大家只要按照这个顺序刷就可以了,**你没看错,就是题目顺序都排好了,文章顺序就是刷题顺序!挨个刷就可以,不用自己再去题海里选题了!** 所以我整理了leetcode刷题攻略一个超级详细的刷题顺序**每道题目都是我精心筛选,都是经典题目高频面试题**,大家只要按照这个顺序刷就可以了,**你没看错,就是题目顺序都排好了,文章顺序就是刷题顺序!挨个刷就可以,不用自己再去题海里选题了!**
@ -49,15 +55,18 @@
**目前已经更新了,数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心,八个专题了,正在讲解动态规划!** **目前已经更新了,数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心,八个专题了,正在讲解动态规划!**
在刷题指南中,每个专题开始都有理论基础篇,并不像是教科书般的理论介绍,而是从实战中归纳需要的基础知识。每个专题结束都有总结篇,最这个专题的归纳总结。 在刷题攻略中,每个专题开始都有理论基础篇,并不像是教科书般的理论介绍,而是从实战中归纳需要的基础知识。每个专题结束都有总结篇,最这个专题的归纳总结。
如果你是算法老手,这篇攻略也是复习的最佳资料,如果把每个系列对应的总结篇,快速过一遍,整个算法知识体系以及各种解法就重现脑海了。 如果你是算法老手,这篇攻略也是复习的最佳资料,如果把每个系列对应的总结篇,快速过一遍,整个算法知识体系以及各种解法就重现脑海了。
在按照如下顺序刷题的过程中,每一道题解一定要看对应文章下面的留言(留言目前只能在手机端查看)。
如果你有疑问或者发现文章哪里有不对的地方,都可以在留言区都能找到答案,还有很多录友的总结非常赞,看完之后也很有收获 目前「代码随想录」刷题攻略更新了:**200多篇文章精讲了200道经典算法题目共60w字的详细图解部分难点题目还搭配了20分钟左右的视频讲解**
目前「代码随想录」刷题指南更新了:**200多篇文章精讲了200道经典算法题目共60w字的详细图解部分难点题目还搭配了20分钟左右的视频讲解**。 **这里每一篇题解,都是精品,值得仔细琢磨**
我在题目讲解中统一用C++语言但你会发现下面几乎每篇题解都配有其他语言版本Java、Python、Go、JavaScript等等这正是热心小伙们的贡献的代码当然我也会严格把控代码质量。
**所以也欢迎大家参与进来,完善题解的各个语言版本,拥抱开源,让更多小伙伴们收益**
准备好了么刷题攻略开始咯go go go 准备好了么刷题攻略开始咯go go go
@ -66,7 +75,7 @@
## 前序 ## 前序
* [「代码随想录」后序安排](https://mp.weixin.qq.com/s/4eeGJREy6E-v6D7cR_5A4g) * [「代码随想录」后序安排](https://mp.weixin.qq.com/s/4eeGJREy6E-v6D7cR_5A4g)
* [「代码随想录」学习社区](https://mp.weixin.qq.com/s/X1XCH-KevURi3LnakJsCkA) * [「代码随想录」学习社区](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
* 编程语言 * 编程语言
@ -119,8 +128,9 @@
4. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) 4. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md)
5. [链表:两两交换链表中的节点](./problems/0024.两两交换链表中的节点.md) 5. [链表:两两交换链表中的节点](./problems/0024.两两交换链表中的节点.md)
6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) 6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md)
7. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) 7. [链表:链表相交](./problems/面试题02.07.链表相交.md)
8. [链表:总结篇!](./problems/链表总结篇.md) 8. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md)
9. [链表:总结篇!](./problems/链表总结篇.md)
## 哈希表 ## 哈希表
@ -156,11 +166,13 @@
3. [字符串:替换空格](./problems/剑指Offer05.替换空格.md) 3. [字符串:替换空格](./problems/剑指Offer05.替换空格.md)
4. [字符串:花式反转还不够!](./problems/0151.翻转字符串里的单词.md) 4. [字符串:花式反转还不够!](./problems/0151.翻转字符串里的单词.md)
5. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md) 5. [链表:听说过两天反转链表又写不出来了?](./problems/0206.翻转链表.md)
6. [链表:环找到了,那入口呢?](./problems/0142.环形链表II.md) 6. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md)
7. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md) 7. [链表:链表相交](./problems/面试题02.07.链表相交.md)
8. [哈希表:解决了两数之和,那么能解决三数之和么](./problems/0015.三数之和.md) 8. [链表:环找到了,那入口呢](./problems/0142.环形链表II.md)
9. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md) 9. [链表:删除链表的倒数第 N 个结点](./problems/0019.删除链表的倒数第N个节点.md)
10. [双指针法:总结篇!](./problems/双指针总结.md) 10. [哈希表:解决了两数之和,那么能解决三数之和么?](./problems/0015.三数之和.md)
11. [双指针法:一样的道理,能解决四数之和](./problems/0018.四数之和.md)
12. [双指针法:总结篇!](./problems/双指针总结.md)
## 栈与队列 ## 栈与队列

View File

@ -162,6 +162,33 @@ class Solution {
return deque.isEmpty(); return deque.isEmpty();
} }
} }
// 方法2
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
Map<Character, Character> map = new HashMap<Character, Character>() {
{
put('}', '{');
put(']', '[');
put(')', '(');
}
};
for (Character c : s.toCharArray()) { // 顺序读取字符
if (!stack.isEmpty() && map.containsKey(c)) { // 是右括号 && 栈不为空
if (stack.peek() == map.get(c)) { // 取其对应的左括号直接和栈顶比
stack.pop(); // 相同则抵消,出栈
} else {
return false; // 不同则直接返回
}
} else {
stack.push(c); // 左括号,直接入栈
}
}
return stack.isEmpty(); // 看左右是否抵消完
}
}
``` ```
Python Python

View File

@ -87,6 +87,46 @@ public:
Java Java
```Java
// 递归版本
class Solution {
public ListNode swapPairs(ListNode head) {
// base case 退出提交
if(head == null || head.next == null) return head;
// 获取当前节点的下一个节点
ListNode next = head.next;
// 进行递归
ListNode newNode = swapPairs(next.next);
// 这里进行交换
next.next = head;
head.next = newNode;
return next;
}
}
```
```java
// 虚拟头结点
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyNode = new ListNode(0);
dummyNode.next = head;
ListNode prev = dummyNode;
while (prev.next != null && prev.next.next != null) {
ListNode temp = head.next.next; // 缓存 next
prev.next = head.next; // 将 prev 的 next 改为 head 的 next
head.next.next = head; // 将 head.next(prev.next) 的next指向 head
head.next = temp; // 将head 的 next 接上缓存的temp
prev = head; // 步进1位
head = head.next; // 步进1位
}
return dummyNode.next;
}
}
```
Python Python

View File

@ -116,7 +116,7 @@ public:
**大家要仔细看注释思考为什么要写while(left <= right) 为什么要写right = middle - 1** **大家要仔细看注释思考为什么要写while(left <= right) 为什么要写right = middle - 1**
``` ```C++
class Solution { class Solution {
public: public:
int searchInsert(vector<int>& nums, int target) { int searchInsert(vector<int>& nums, int target) {
@ -158,7 +158,7 @@ public:
**大家要仔细看注释思考为什么要写while (left < right) 为什么要写right = middle**。 **大家要仔细看注释思考为什么要写while (left < right) 为什么要写right = middle**。
``` ```C++
class Solution { class Solution {
public: public:
int searchInsert(vector<int>& nums, int target) { int searchInsert(vector<int>& nums, int target) {

View File

@ -175,7 +175,22 @@ class Solution {
``` ```
Python Python
```python
class Solution:
def jump(self, nums: List[int]) -> int:
if len(nums) == 1: return 0
ans = 0
curDistance = 0
nextDistance = 0
for i in range(len(nums)):
nextDistance = max(i + nums[i], nextDistance)
if i == curDistance:
if curDistance != len(nums) - 1:
ans += 1
curDistance = nextDistance
if nextDistance >= len(nums) - 1: break
return ans
```
Go Go

View File

@ -149,6 +149,7 @@ public:
Java Java
```java ```java
class Solution { class Solution {
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合 List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果 LinkedList<Integer> path = new LinkedList<>();// 用来存放符合条件结果
boolean[] used; boolean[] used;
@ -167,9 +168,6 @@ class Solution {
return; return;
} }
for (int i = 0; i < nums.length; i++){ for (int i = 0; i < nums.length; i++){
// if (path.contains(nums[i])){
// continue;
// }
if (used[i]){ if (used[i]){
continue; continue;
} }
@ -187,6 +185,26 @@ Python
Go Go
```Go
var result [][]int
func backtrack(nums,pathNums []int,used []bool){
if len(nums)==len(pathNums){
tmp:=make([]int,len(nums))
copy(tmp,pathNums)
result=append(result,tmp)
//result=append(result,pathNums)
return
}
for i:=0;i<len(nums);i++{
if !used[i]{
used[i]=true
pathNums=append(pathNums,nums[i])
backtrack(nums,pathNums,used)
pathNums=pathNums[:len(pathNums)-1]
used[i]=false
}
}
}
Javascript: Javascript:

View File

@ -85,7 +85,7 @@ public:
path.clear(); path.clear();
sort(nums.begin(), nums.end()); // 排序 sort(nums.begin(), nums.end()); // 排序
vector<bool> used(nums.size(), false); vector<bool> used(nums.size(), false);
backtracking(nums, vec, used); backtracking(nums, used);
return result; return result;
} }
}; };

View File

@ -363,7 +363,72 @@ Python
Go Go
```Go
import "strings"
var res [][]string
func isValid(board [][]string, row, col int) (res bool){
n := len(board)
for i:=0; i < row; i++ {
if board[i][col] == "Q" {
return false
}
}
for i := 0; i < n; i++{
if board[row][i] == "Q" {
return false
}
}
for i ,j := row, col; i >= 0 && j >=0 ; i, j = i - 1, j- 1{
if board[i][j] == "Q"{
return false
}
}
for i, j := row, col; i >=0 && j < n; i,j = i-1, j+1 {
if board[i][j] == "Q" {
return false
}
}
return true
}
func backtrack(board [][]string, row int) {
size := len(board)
if row == size{
temp := make([]string, size)
for i := 0; i<size;i++{
temp[i] = strings.Join(board[i],"")
}
res =append(res,temp)
return
}
for col := 0; col < size; col++ {
if !isValid(board, row, col){
continue
}
board[row][col] = "Q"
backtrack(board, row+1)
board[row][col] = "."
}
}
func solveNQueens(n int) [][]string {
res = [][]string{}
board := make([][]string, n)
for i := 0; i < n; i++{
board[i] = make([]string, n)
}
for i := 0; i < n; i++{
for j := 0; j<n;j++{
board[i][j] = "."
}
}
backtrack(board, 0)
return res
}
```

View File

@ -175,31 +175,25 @@ class Solution:
``` ```
Go Go
```Go
func maxSubArray(nums []int) int {
if len(nums)<1{
return 0
}
dp:=make([]int,len(nums))
result:=nums[0]
dp[0]=nums[0]
for i:=1;i<len(nums);i++{
dp[i]=max(dp[i-1]+nums[i],nums[i])
result=max(dp[i],result)
}
return result
}
func max(a,b int)int{ ```go
if a>b{ func maxSubArray(nums []int) int {
return a maxSum := nums[0]
}else{ for i := 1; i < len(nums); i++ {
return b if nums[i] + nums[i-1] > nums[i] {
nums[i] += nums[i-1]
}
if nums[i] > maxSum {
maxSum = nums[i]
}
} }
return maxSum
} }
``` ```
----------------------- -----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -212,7 +212,45 @@ public:
Java Java
```Java
class Solution {
public int climbStairs(int n) {
// 跟斐波那契数列一样
if(n <= 2) return n;
int a = 1, b = 2, sum = 0;
for(int i = 3; i <= n; i++){
sum = a + b;
a = b;
b = sum;
}
return b;
}
}
```
```java
// 常规方式
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
// 用变量记录代替数组
public int climbStairs(int n) {
int a = 0, b = 1, c = 0; // 默认需要1次
for (int i = 1; i <= n; i++) {
c = a + b; // f(i - 1) + f(n - 2)
a = b; // 记录上一轮的值
b = c; // 向后步进1个数
}
return c;
}
```
Python Python

View File

@ -198,13 +198,71 @@ public:
Java Java
```java
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m + 1][n + 1];
// 初始化
for (int i = 1; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 1; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// 因为dp数组有效位从1开始
// 所以当前遍历到的字符串的位置为i-1 | j-1
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1;
}
}
}
return dp[m][n];
}
```
Python Python
Go Go
```Go
func minDistance(word1 string, word2 string) int {
m, n := len(word1), len(word2)
dp := make([][]int, m+1)
for i := range dp {
dp[i] = make([]int, n+1)
}
for i := 0; i < m+1; i++ {
dp[i][0] = i // word1[i] 变成 word2[0], 删掉 word1[i], 需要 i 部操作
}
for j := 0; j < n+1; j++ {
dp[0][j] = j // word1[0] 变成 word2[j], 插入 word1[j],需要 j 部操作
}
for i := 1; i < m+1; i++ {
for j := 1; j < n+1; j++ {
if word1[i-1] == word2[j-1] {
dp[i][j] = dp[i-1][j-1]
} else { // Min(插入,删除,替换)
dp[i][j] = Min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
}
}
}
return dp[m][n]
}
func Min(args ...int) int {
min := args[0]
for _, item := range args {
if item < min {
min = item
}
}
return min
}
```

View File

@ -373,6 +373,32 @@ Python
Go Go
```Go
var res [][]int
func combine(n int, k int) [][]int {
res=[][]int{}
if n <= 0 || k <= 0 || k > n {
return res
}
backtrack(n, k, 1, []int{})
return res
}
func backtrack(n,k,start int,track []int){
if len(track)==k{
temp:=make([]int,k)
copy(temp,track)
res=append(res,temp)
}
if len(track)+n-start+1 < k {
return
}
for i:=start;i<=n;i++{
track=append(track,i)
backtrack(n,k,i+1,track)
track=track[:len(track)-1]
}
}
```

View File

@ -189,7 +189,18 @@ Python
Go Go
```Go
func numTrees(n int)int{
dp:=make([]int,n+1)
dp[0]=1
for i:=1;i<=n;i++{
for j:=1;j<=i;j++{
dp[i]+=dp[j-1]*dp[i-j]
}
}
return dp[n]
}
```

View File

@ -304,6 +304,35 @@ class Solution {
return true; return true;
} }
} }
// 简洁实现·递归解法
class Solution {
public boolean isValidBST(TreeNode root) {
return validBST(Long.MIN_VALUE, Long.MAX_VALUE, root);
}
boolean validBST(long lower, long upper, TreeNode root) {
if (root == null) return true;
if (root.val <= lower || root.val >= upper) return false;
return validBST(lower, root.val, root.left) && validBST(root.val, upper, root.right);
}
}
// 简洁实现·中序遍历
class Solution {
private long prev = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
if (!isValidBST(root.left)) {
return false;
}
if (root.val <= prev) { // 不满足二叉搜索树条件
return false;
}
prev = root.val;
return isValidBST(root.right);
}
}
``` ```
Python Python

View File

@ -657,8 +657,36 @@ Python
Go Go
```Go
func levelOrder(root *TreeNode) [][]int {
result:=make([][]int,0)
if root==nil{
return result
}
queue:=make([]*TreeNode,0)
queue=append(queue,root)
for len(queue)>0{
list:=make([]int,0)
l:=len(queue)
for i:=0;i<l;i++{
level:=queue[0]
queue=queue[1:]
list=append(list,level.Val)
if level.Left!=nil{
queue=append(queue,level.Left)
}
if level.Right!=nil{
queue=append(queue,level.Right)
}
}
result=append(result,list)
}
return result
}
```
----------------------- -----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -623,7 +623,21 @@ Python
Go Go
JavaScript
```javascript
var buildTree = function(inorder, postorder) {
if (!postorder.length) return null
let root = new TreeNode(postorder[postorder.length - 1])
let index = inorder.findIndex(number => number === root.val)
root.left = buildTree(inorder.slice(0, index), postorder.slice(0, index))
root.right = buildTree(inorder.slice(index + 1, inorder.length), postorder.slice(index, postorder.length - 1))
return root
};
```
----------------------- -----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)

View File

@ -332,6 +332,19 @@ class Solution {
} }
} }
// LC112 简洁方法
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false; // 为空退出
// 叶子节点判断是否符合
if (root.left == null && root.right == null) return root.val == targetSum;
// 求两侧分支的路径和
return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);
}
}
``` ```
Python Python

View File

@ -198,12 +198,52 @@ public:
Java Java
```java
class Solution {
public int maxProfit(int[] prices) {
int minprice = Integer.MAX_VALUE;
int maxprofit = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < minprice) {
minprice = prices[i];
} else if (prices[i] - minprice > maxprofit) {
maxprofit = prices[i] - minprice;
}
}
return maxprofit;
}
}
```
Python Python
Go Go
```Go
func maxProfit(prices []int) int {
length:=len(prices)
if length==0{return 0}
dp:=make([][]int,length)
for i:=0;i<length;i++{
dp[i]=make([]int,2)
}
dp[0][0]=-prices[0]
dp[0][1]=0
for i:=1;i<length;i++{
dp[i][0]=max(dp[i-1][0],-prices[i])
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i])
}
return dp[length-1][1]
}
func max(a,b int)int {
if a>b{
return a
}
return b
}
```

View File

@ -133,7 +133,41 @@ public:
Java Java
```java
// 动态规划
class Solution
// 实现1二维数组存储
// 可以将每天持有与否的情况分别用 dp[i][0] 和 dp[i][1] 来进行存储
// 时间复杂度O(n)空间复杂度O(n)
public int maxProfit(int[] prices) {
int n = prices.length;
int[][] dp = new int[n][2]; // 创建二维数组存储状态
dp[0][0] = 0; // 初始状态
dp[0][1] = -prices[0];
for (int i = 1; i < n; ++i) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); // 第 i 天,没有股票
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); // 第 i 天,持有股票
}
return dp[n - 1][0]; // 卖出股票收益高于持有股票收益,因此取[0]
}
// 实现2变量存储
// 第一种方法需要用二维数组存储,有空间开销,其实关心的仅仅是前一天的状态,不关注更多的历史信息
// 因此,可以仅保存前一天的信息存入 dp0、dp1 这 2 个变量即可
// 时间复杂度O(n)空间复杂度O(1)
public int maxProfit(int[] prices) {
int n = prices.length;
int dp0 = 0, dp1 = -prices[0]; // 定义变量,存储初始状态
for (int i = 1; i < n; ++i) {
int newDp0 = Math.max(dp0, dp1 + prices[i]); // 第 i 天,没有股票
int newDp1 = Math.max(dp1, dp0 - prices[i]); // 第 i 天,持有股票
dp0 = newDp0;
dp1 = newDp1;
}
return dp0;
}
}
```
Python Python

View File

@ -223,7 +223,21 @@ class Solution {
``` ```
Python Python
```python
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
start = 0
curSum = 0
totalSum = 0
for i in range(len(gas)):
curSum += gas[i] - cost[i]
totalSum += gas[i] - cost[i]
if curSum < 0:
curSum = 0
start = i + 1
if totalSum < 0: return -1
return start
```
Go Go
@ -234,4 +248,4 @@ Go
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div> <div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>

View File

@ -161,7 +161,18 @@ class Solution {
``` ```
Python Python
```python
class Solution:
def candy(self, ratings: List[int]) -> int:
candyVec = [1] * len(ratings)
for i in range(1, len(ratings)):
if ratings[i] > ratings[i - 1]:
candyVec[i] = candyVec[i - 1] + 1
for j in range(len(ratings) - 2, -1, -1):
if ratings[j] > ratings[j + 1]:
candyVec[j] = max(candyVec[j], candyVec[j + 1] + 1)
return sum(candyVec)
```
Go Go
@ -172,4 +183,4 @@ Go
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div> <div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>

View File

@ -170,7 +170,32 @@ public class EvalRPN {
} }
``` ```
Go:
```Go
func evalRPN(tokens []string) int {
stack := []int{}
for _, token := range tokens {
val, err := strconv.Atoi(token)
if err == nil {
stack = append(stack, val)
} else {
num1, num2 := stack[len(stack)-2], stack[(len(stack))-1]
stack = stack[:len(stack)-2]
switch token {
case "+":
stack = append(stack, num1+num2)
case "-":
stack = append(stack, num1-num2)
case "*":
stack = append(stack, num1*num2)
case "/":
stack = append(stack, num1/num2)
}
}
}
return stack[0]
}
```

View File

@ -141,7 +141,8 @@ void reverse(string& s, int start, int end) {
<img src='https://code-thinking.cdn.bcebos.com/pics/151_%E7%BF%BB%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%87%8C%E7%9A%84%E5%8D%95%E8%AF%8D.png' width=600> </img></div> <img src='https://code-thinking.cdn.bcebos.com/pics/151_%E7%BF%BB%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%87%8C%E7%9A%84%E5%8D%95%E8%AF%8D.png' width=600> </img></div>
``` ```C++
// 版本一
class Solution { class Solution {
public: public:
// 反转字符串s中左闭又闭的区间[start, end] // 反转字符串s中左闭又闭的区间[start, end]
@ -182,7 +183,7 @@ public:
int end = 0; // 反转的单词在字符串里终止位置 int end = 0; // 反转的单词在字符串里终止位置
bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间 bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
for (int i = 0; i < s.size(); i++) { // 开始反转单词 for (int i = 0; i < s.size(); i++) { // 开始反转单词
if ((!entry) || (s[i] != ' ' && s[i - 1] == ' ')) { if ((!entry))) {
start = i; // 确定单词起始位置 start = i; // 确定单词起始位置
entry = true; // 进入单词区间 entry = true; // 进入单词区间
} }
@ -201,9 +202,42 @@ public:
} }
return s; return s;
} }
/* 主函数简单写法
string reverseWords(string s) {
removeExtraSpaces(s);
reverse(s, 0, s.size() - 1);
for(int i = 0; i < s.size(); i++) {
int j = i;
// 查找单词间的空格,翻转单词
while(j < s.size() && s[j] != ' ') j++;
reverse(s, i, j - 1);
i = j;
}
return s;
}
*/
}; };
``` ```
当然这里的主函数reverseWords写的有一些冗余的可以精简一些精简之后的主函数为
```C++
// 注意这里仅仅是主函数,其他函数和版本一一致
string reverseWords(string s) {
removeExtraSpaces(s);
reverse(s, 0, s.size() - 1);
for(int i = 0; i < s.size(); i++) {
int j = i;
// 查找单词间的空格,翻转单词
while(j < s.size() && s[j] != ' ') j++;
reverse(s, i, j - 1);
i = j;
}
return s;
}
```

View File

@ -111,7 +111,24 @@ public:
Java Java
```Java
// 动态规划
class Solution {
public int rob(int[] nums) {
if (nums == null || nums.length == 0) return 0;
if (nums.length == 1) return nums[0];
int[] dp = new int[nums.length + 1];
dp[0] = nums[0];
dp[1] = Math.max(dp[0], nums[1]);
for (int i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[nums.length - 1];
}
}
```
Python Python

View File

@ -98,7 +98,28 @@ public:
Java Java
```Java
class Solution {
public int rob(int[] nums) {
if (nums == null || nums.length == 0)
return 0;
int len = nums.length;
if (len == 1)
return nums[0];
return Math.max(robAction(nums, 0, len - 1), robAction(nums, 1, len));
}
int robAction(int[] nums, int start, int end) {
int x = 0, y = 0, z = 0;
for (int i = start; i < end; i++) {
y = z;
z = Math.max(y, x + nums[i]);
x = y;
}
return z;
}
}
```
Python Python

View File

@ -266,7 +266,34 @@ Python
Go Go
```Go
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
// check
if root == nil {
return root
}
// 相等 直接返回root节点即可
if root == p || root == q {
return root
}
// Divide
left := lowestCommonAncestor(root.Left, p, q)
right := lowestCommonAncestor(root.Right, p, q)
// Conquer
// 左右两边都不为空,则根节点为祖先
if left != nil && right != nil {
return root
}
if left != nil {
return left
}
if right != nil {
return right
}
return nil
}
```
@ -274,4 +301,4 @@ Go
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div> <div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>

View File

@ -77,7 +77,7 @@ if (cur->left == NULL && cur->right == NULL) {
这里我们先使用vector<int>结构的path容器来记录路径那么终止处理逻辑如下 这里我们先使用vector<int>结构的path容器来记录路径那么终止处理逻辑如下
``` ```C++
if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点 if (cur->left == NULL && cur->right == NULL) { // 遇到叶子节点
string sPath; string sPath;
for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式 for (int i = 0; i < path.size() - 1; i++) { // 将path里记录的路径转为string格式
@ -113,7 +113,7 @@ if (cur->right) {
那么回溯要怎么回溯呢,一些同学会这么写,如下: 那么回溯要怎么回溯呢,一些同学会这么写,如下:
``` ```C++
if (cur->left) { if (cur->left) {
traversal(cur->left, path, result); traversal(cur->left, path, result);
} }
@ -129,7 +129,7 @@ path.pop_back();
那么代码应该这么写: 那么代码应该这么写:
``` ```C++
if (cur->left) { if (cur->left) {
traversal(cur->left, path, result); traversal(cur->left, path, result);
path.pop_back(); // 回溯 path.pop_back(); // 回溯
@ -335,4 +335,4 @@ Go
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div> <div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>

View File

@ -98,8 +98,6 @@ public:
}; };
``` ```
杨老师的这个专栏很不错他本身也是Oracle 首席工程师对Java有极其深刻的理解讲的内容很硬核适合使用Java语言的录友们用来进阶作为面试突击手册非常合适 所以推荐给大家现在下单输入口令javahexin可以省40元那[机智]
## 总结 ## 总结
本题最关键的是要想到dp[i]由哪些状态可以推出来并取最大值那么很自然就能想到递推公式dp[i] = max(dp[i], dp[j] + 1); 本题最关键的是要想到dp[i]由哪些状态可以推出来并取最大值那么很自然就能想到递推公式dp[i] = max(dp[i], dp[j] + 1);
@ -110,14 +108,58 @@ public:
Java Java
```Java
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int res = 0;
for (int i = 0; i < dp.length; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
}
```
Python Python
Go Go
```go
func lengthOfLIS(nums []int ) int {
dp := []int{}
for _, num := range nums {
if len(dp) ==0 || dp[len(dp) - 1] < num {
dp = append(dp, num)
} else {
l, r := 0, len(dp) - 1
pos := r
for l <= r {
mid := (l + r) >> 1
if dp[mid] >= num {
pos = mid;
r = mid - 1
} else {
l = mid + 1
}
}
dp[pos] = num
}//二分查找
}
return len(dp)
}
```
*复杂度分析*
- 时间复杂度O(nlogn)。数组 nums 的长度为 n我们依次用数组中的元素去更新 dp 数组,相当于插入最后递增的元素,而更新 dp 数组时需要进行 O(logn) 的二分搜索,所以总时间复杂度为 O(nlogn)。
- 空间复杂度O(n),需要额外使用长度为 n 的 dp 数组。
----------------------- -----------------------

View File

@ -218,7 +218,72 @@ public:
Java Java
```Java
class Solution {
// 1.递归去偷,超时
public int rob(TreeNode root) {
if (root == null)
return 0;
int money = root.val;
if (root.left != null) {
money += rob(root.left.left) + rob(root.left.right);
}
if (root.right != null) {
money += rob(root.right.left) + rob(root.right.right);
}
return Math.max(money, rob(root.left) + rob(root.right));
}
// 2.递归去偷,记录状态
// 执行用时3 ms , 在所有 Java 提交中击败了 56.24% 的用户
public int rob1(TreeNode root) {
Map<TreeNode, Integer> memo = new HashMap<>();
return robAction(root, memo);
}
int robAction(TreeNode root, Map<TreeNode, Integer> memo) {
if (root == null)
return 0;
if (memo.containsKey(root))
return memo.get(root);
int money = root.val;
if (root.left != null) {
money += robAction(root.left.left, memo) + robAction(root.left.right, memo);
}
if (root.right != null) {
money += robAction(root.right.left, memo) + robAction(root.right.right, memo);
}
int res = Math.max(money, robAction(root.left, memo) + robAction(root.right, memo));
memo.put(root, res);
return res;
}
// 3.状态标记递归
// 执行用时0 ms , 在所有 Java 提交中击败了 100% 的用户
// 不偷Max(左孩子不偷,左孩子偷) + Max(又孩子不偷,右孩子偷)
// root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) +
// Math.max(rob(root.right)[0], rob(root.right)[1])
// 偷:左孩子不偷+ 右孩子不偷 + 当前节点偷
// root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;
public int rob3(TreeNode root) {
int[] res = robAction1(root);
return Math.max(res[0], res[1]);
}
int[] robAction1(TreeNode root) {
int res[] = new int[2];
if (root == null)
return res;
int[] left = robAction1(root.left);
int[] right = robAction1(root.right);
res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
res[1] = root.val + left[0] + right[0];
return res;
}
}
```
Python Python

View File

@ -171,7 +171,20 @@ public:
Java Java
```Java
class Solution {
public int fib(int n) {
if (n < 2) return n;
int a = 0, b = 1, c = 0;
for (int i = 1; i < n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
}
```
Python Python

View File

@ -227,6 +227,30 @@ Python
Go Go
```Go
func countSubstrings(s string) int {
res:=0
dp:=make([][]bool,len(s))
for i:=0;i<len(s);i++{
dp[i]=make([]bool,len(s))
}
for i:=len(s)-1;i>=0;i--{
for j:=i;j<len(s);j++{
if s[i]==s[j]{
if j-i<=1{
res++
dp[i][j]=true
}else if dp[i+1][j-1]{
res++
dp[i][j]=true
}
}
}
}
return res
}
```

View File

@ -271,6 +271,20 @@ class Solution:
Go Go
```Go
func insertIntoBST(root *TreeNode, val int) *TreeNode {
if root == nil {
root = &TreeNode{Val: val}
return root
}
if root.Val > val {
root.Left = insertIntoBST(root.Left, val)
} else {
root.Right = insertIntoBST(root.Right, val)
}
return root
}
```
@ -279,4 +293,4 @@ Go
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div> <div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>

View File

@ -124,7 +124,18 @@ class Solution {
``` ```
Python Python
```python
class Solution:
def largestSumAfterKNegations(self, A: List[int], K: int) -> int:
A = sorted(A, key=abs, reverse=True) # 将A按绝对值从大到小排列
for i in range(len(A)):
if K > 0 and A[i] < 0:
A[i] *= -1
K -= 1
if K > 0:
A[len(A) - 1] *= ((-1)**K)
return sum(A)
```
Go Go
@ -135,4 +146,4 @@ Go
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321) * B站视频[代码随想录](https://space.bilibili.com/525438321)
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ) * 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div> <div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>

View File

@ -115,7 +115,59 @@ void traversal(TreeNode* cur, vector<int>& vec) {
Java Java
```Java
// 前序遍历·递归·LC144_二叉树的前序遍历
class Solution {
ArrayList<Integer> preOrderReverse(TreeNode root) {
ArrayList<Integer> result = new ArrayList<Integer>();
preOrder(root, result);
return result;
}
void preOrder(TreeNode root, ArrayList<Integer> result) {
if (root == null) {
return;
}
result.add(root.val); // 注意这一句
preOrder(root.left, result);
preOrder(root.right, result);
}
}
// 中序遍历·递归·LC94_二叉树的中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
inorder(root, res);
return res;
}
void inorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
inorder(root.left, list);
list.add(root.val); // 注意这一句
inorder(root.right, list);
}
}
// 后序遍历·递归·LC145_二叉树的后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorder(root, res);
return res;
}
void postorder(TreeNode root, List<Integer> list) {
if (root == null) {
return;
}
postorder(root.left, list);
postorder(root.right, list);
list.add(root.val); // 注意这一句
}
}
```
Python Python

View File

@ -9,15 +9,17 @@
-------------------------- --------------------------
# 看了这么多代码,谈一谈代码风格! # 看了这么多代码,谈一谈代码风格!
其实在交流群里经常能看到大家发出来的代码,可以看出很多录友代码规范应该不甚了解,代码看起来并不舒服 最近看了很多录友在[leetcode-master](https://mp.weixin.qq.com/s/wZRTrA9Rbvgq1yEkSw4vfQ)上提交的代码,发现很多录友代码其实并不规范,这一点平时在交流群和知识星球里也能看出来
很多录友对代码规范应该不甚了解,代码看起来并不舒服。
所以呢我给大家讲一讲代码规范我主要以C++代码为例。 所以呢我给大家讲一讲代码规范我主要以C++代码为例。
需要强调一下,代码规范并不是仅仅是让代码看着舒服,这是一个很重要的习惯。 需要强调一下,代码规范并不是仅仅是让代码看着舒服,这是一个很重要的习惯。
# 题外话 ## 题外话
工作之后,**特别是在大厂,看谁的技术牛不牛逼,不用看谁写出多牛逼的代码,就代码风格扫一眼,立刻就能看出来是正规军还是野生程序员**。 工作之后,**特别是在大厂,看谁的技术牛不牛逼,不用看谁写出多牛逼的代码,就代码风格扫一眼,立刻就能看出来是正规军还是野生程序员**。
@ -25,15 +27,15 @@
现在一些小公司,甚至大公司里的某些技术团队也不注重代码规范,赶进度撸出功能就完事,这种情况就要分两方面看: 现在一些小公司,甚至大公司里的某些技术团队也不注重代码规范,赶进度撸出功能就完事,这种情况就要分两方面看:
* 第一种情况:这个项目在业务上赚到钱每年年终好几十万那项目前期还关心啥代码风格赶进度把功能撸出来赚钱就完事了例如15年的王者荣耀。 * 第一种情况:这个项目在业务上具有巨大潜力,需要抢占市场,只要先站住市场就能赚到钱,每年年终好几十万,那项目前期还关心啥代码风格,赶进度把功能撸出来,赚钱就完事了,例如12年的微信15年的王者荣耀。这些项目都是后期在不断优化的。
* 第二种情况:这个项目没赚到钱,半死不活的,代码还没有设计也没有规范,这样对技术人员的伤害就非常大了。 * 第二种情况:这个项目没赚到钱,半死不活的,代码还没有设计也没有规范,这样对技术人员的伤害就非常大了。
**而不注重代码风格的团队99.99%都是第二种情况**,如果你赶上了第一种情况,那就恭喜你了,本文下面的内容可以不用看了,哈哈。 **而不注重代码风格的团队99.99%都是第二种情况**,如果你赶上了第一种情况,那就恭喜你了,本文下面的内容可以不用看了,哈哈。
# 代码规范 ## 代码规范
## 变量命名 ### 变量命名
这里我简单说一说规范问题。 这里我简单说一说规范问题。
@ -67,7 +69,7 @@
![编程风格](https://img-blog.csdnimg.cn/20201119173039835.png) ![编程风格](https://img-blog.csdnimg.cn/20201119173039835.png)
## 水平留白(代码空格) ### 水平留白(代码空格)
经常看到有的同学的代码都堆在一起,看起来都费劲,或者是有的间隔有空格,有的没有空格,很不统一,有的同学甚至为了让代码精简,把所有空格都省略掉了。 经常看到有的同学的代码都堆在一起,看起来都费劲,或者是有的间隔有空格,有的没有空格,很不统一,有的同学甚至为了让代码精简,把所有空格都省略掉了。
@ -89,7 +91,7 @@ int i, j;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++)
``` ```
括号和函数保持同一行,并有一个空格例如: 括号和函数保持同一行,并有一个空格例如:
``` ```
while (n) { while (n) {
@ -123,9 +125,13 @@ public:
}; };
``` ```
当然我并不是说一定要按照Google的规范来代码风格其实统一就行没有严格的说谁对谁错。 这里关于大括号是否要重启一行?
# 总结 Google规范是 大括号和 控制语句保持同一行的,我个人也很认可这种写法,因为可以缩短代码的行数,特别是项目中代码行数很多的情况下,这种写法是可以提高阅读代码的效率。
当然我并不是说一定要按照Google的规范来**代码风格其实统一就行,没有严格的说谁对谁错**。
## 总结
如果还是学生使用C++的话,可以按照题解中我的代码风格来,还是比较标准的。 如果还是学生使用C++的话,可以按照题解中我的代码风格来,还是比较标准的。

View File

@ -118,21 +118,6 @@ public static void test_arr() {
这里面试中数组相关的理论知识就介绍完了。 这里面试中数组相关的理论知识就介绍完了。
后续我将介绍面试中数组相关的五道经典面试题目,敬请期待!
## 其他语言版本
Java
Python
Go
----------------------- -----------------------

View File

@ -0,0 +1,109 @@
<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>
## 面试题 02.07. 链表相交
题目链接https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/
给定两个单向链表判定它们是否相交并返回交点。请注意相交的定义基于节点的引用而不是基于节点的值。换句话说如果一个链表的第k个节点与另一个链表的第j个节点是同一节点引用完全相同则这两个链表相交。
示例 1
输入listA = [4,1,8,4,5], listB = [5,0,1,8,4,5]
输出Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0。从各自的表头开始算起链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
## 思路
本来很简洁明了的一道题,让题目描述搞的云里雾里的。
简单来说,就是求两个链表交点节点的**指针**。 这里同学们要注意,交点不是数值相等,而是指针相等。
为了方便举例,假设节点元素数值相等,则节点指针相等。
看如下两个链表目前curA指向链表A的头结点curB指向链表B的头结点
![面试题02.07.链表相交_1](https://code-thinking.cdn.bcebos.com/pics/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4_1.png)v
我们求出两个链表的长度并求出两个链表长度的差值然后让curA移动到和curB 末尾对齐的位置,如图:
![面试题02.07.链表相交_2](https://code-thinking.cdn.bcebos.com/pics/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4_2.png)
此时我们就可以比较curA和curB是否相同如果不相同同时向后移动curA和curB如果遇到curA == curB则找到焦点。
否则循环退出返回空指针。
C++代码如下:
```C++
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上末尾位置对齐
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
```
* 时间复杂度:$O(n + m)$
* 空间复杂度:$O(1)$
## 其他语言版本
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>