This commit is contained in:
chefyuan 2021-05-05 13:49:56 +08:00
commit f765951ec7
15 changed files with 627 additions and 12 deletions

View File

@ -33,6 +33,8 @@
我们首先将链表的所有元素都保存在数组中然后再利用双指针遍历数组进而来判断是否为回文这个方法很容易理解而且代码实现也比较简单
**题目代码**
```java
class Solution {
public boolean isPalindrome(ListNode head) {
@ -72,6 +74,10 @@ class Solution {
![翻转链表部分](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/翻转链表部分.1v2ncl72ligw.gif)
#### **题目代码**
Java Code
```java
class Solution {
public boolean isPalindrome(ListNode head) {
@ -129,3 +135,63 @@ class Solution {
}
```
C++ Code
```cpp
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return true;
}
//找到中间节点也就是翻转的头节点,这个在昨天的题目中讲到
//但是今天和昨天有一些不一样的地方就是如果有两个中间节点返回第一个昨天的题目是第二个
ListNode * midenode = searchmidnode(head);
//原地翻转链表需要两个辅助指针这个也是面试题目大家可以做一下
//这里我们用的是midnode->next需要注意因为我们找到的是中点但是我们翻转的是后半部分
ListNode * backhalf = reverse(midenode->next);
//遍历两部分链表判断值是否相等
ListNode * p1 = head;
ListNode * p2 = backhalf;
while (p2 != nullptr) {
if (p1->val != p2->val) {
return false;
}
p1 = p1->next;
p2 = p2->next;
}
// 还原链表并返回结果,这一步是需要注意的我们不可以破坏初始结构我们只是判断是否为回文
//当然如果没有这一步也是可以AC但是面试的时候题目要求可能会有这一条
midenode->next = reverse(backhalf);
return true;
}
//找到中间的部分
ListNode * searchmidnode (ListNode * head) {
ListNode * fast = new ListNode(-1);
ListNode * slow = new ListNode(-1);
fast = head;
slow = head;
//找到中点
while (fast->next != nullptr && fast->next->next != nullptr) {
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
//翻转链表
ListNode * reverse (ListNode * slow) {
ListNode * low = nullptr;
ListNode * temp = nullptr;
//翻转链表
while (slow != nullptr) {
temp = slow->next;
slow->next = low;
low = slow;
slow = temp;
}
return low;
}
};
```

View File

@ -72,3 +72,24 @@ var hasCycle = function(head) {
return false;
};
```
C++ Code:
```cpp
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode * fast = head;
ListNode * low = head;
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next;
low = low->next;
if (fast == low) {
return true;
}
}
return false;
}
};
```

View File

@ -123,7 +123,9 @@ public class Solution {
![环形链表2](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/环形链表2.elwu1pw2lw0.gif)
**题目代码**
Java Code:
```java
public class Solution {
@ -153,3 +155,34 @@ public class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
//快慢指针
ListNode * fast = head;
ListNode * low = head;
//设置循环条件
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next;
low = low->next;
//相遇
if (fast == low) {
//设置一个新的指针从头节点出发慢指针速度为1所以可以使用慢指针从相遇点出发
ListNode * newnode = head;
while (newnode != low) {
low = low->next;
newnode = newnode->next;
}
//在环入口相遇
return low;
}
}
return nullptr;
}
};
```

View File

@ -82,6 +82,8 @@
**题目代码**
Java Code:
```java
class Solution {
public ListNode insertionSortList(ListNode head) {
@ -121,7 +123,45 @@ class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
if (head == nullptr && head->next == nullptr) {
return head;
}
//哑节点
ListNode * dummyNode = new ListNode(-1);
dummyNode->next = head;
//pre负责指向新元素last 负责指向新元素的前一元素
//判断是否需要执行插入操作
ListNode * pre = head->next;
ListNode * last = head;
ListNode * temphead = dummyNode;
while (pre != nullptr) {
//不需要插入到合适位置则继续往下移动
if (last->val <= pre->val) {
pre = pre->next;
last = last->next;
continue;
}
//开始出发查找新元素的合适位置
temphead = dummyNode;
while (temphead->next->val <= pre->val) {
temphead = temphead->next;
}
//此时我们已经找到了合适位置我们需要进行插入大家可以画一画
last->next = pre->next;
pre->next = temphead->next;
temphead->next = pre;
pre = last->next;
}
return dummyNode->next;
}
};
```

View File

@ -33,6 +33,10 @@ low = temp 即可。然后重复执行上诉操作直至最后,这样则完成
我会对每个关键点进行注释大家可以参考动图理解
**题目代码**
Java Code:
```java
class Solution {
@ -81,8 +85,44 @@ var reverseList = function(head) {
};
```
C++代码
```cpp
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//特殊情况
if (head == nullptr || head->next == nullptr) {
return head;
}
//反转
return reverse(head);
}
ListNode * reverse (ListNode * head) {
ListNode * low = nullptr;
ListNode * pro = head;
while (pro != nullptr) {
//代表橙色指针
ListNode * temp = pro;
//移动绿色指针
pro = pro->next;
//反转节点
temp->next = low;
//移动黄色指针
low = temp;
}
return low;
}
};
```
上面的迭代写法是不是搞懂啦现在还有一种递归写法不是特别容易理解刚开始刷题的同学可以只看迭代解法
**题目代码**
Java Code:
```java
class Solution {
@ -118,3 +158,26 @@ var reverseList = function(head) {
};
```
C++代码:
```cpp
class Solution {
public:
ListNode * reverseList(ListNode * head) {
//结束条件
if (head == nullptr || head->next == nullptr) {
return head;
}
//保存最后一个节点
ListNode * pro = reverseList(head->next);
//将节点进行反转我们可以这样理解 4->next->next = 4;
//4->next = 5
// 5->next = 4 则实现了反转
head->next->next = head;
//防止循环
head->next = nullptr;
return pro;
}
};
```

View File

@ -36,6 +36,8 @@
#### 题目代码
Java Code:
```java
class Solution {
public ListNode oddEvenList(ListNode head) {
@ -60,3 +62,30 @@ class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode * odd = head;
ListNode * even = head->next;
ListNode * evenhead = even;
while (odd->next != nullptr && even->next != nullptr) {
//将偶数位合在一起奇数位合在一起
odd->next = even->next;
odd = odd->next;
even->next = odd->next;
even = even->next;
}
//链接
odd->next = evenhead;
return head;
}
};
```

View File

@ -39,6 +39,10 @@
![删除重复节点2](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/删除重复节点2.3btmii5cgxa0.gif)
**题目代码**
Java Code:
```java
class Solution {
public ListNode deleteDuplicates(ListNode head) {
@ -68,3 +72,35 @@ class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr || head->next == nullptr){
return head;
}
ListNode * pre = head;
ListNode * low = new ListNode(0);
low->next = pre;
ListNode * ret = new ListNode(-1);
ret = low;
while(pre != nullptr && pre->next != nullptr) {
if (pre->val == pre->next->val) {
while (pre != nullptr && pre->next != nullptr && pre->val == pre->next->val) {
pre = pre->next;
}
pre = pre->next;
low->next = pre;
}
else{
pre = pre->next;
low = low->next;
}
}
return ret->next;
}
};
```

View File

@ -34,6 +34,8 @@
**题目代码**
Java Code:
```java
/**
* Definition for singly-linked list.
@ -75,7 +77,41 @@ class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
if (head == nullptr) {
return head;
}
ListNode * pro = head;
ListNode * big = new ListNode(-1);
ListNode * small = new ListNode(-1);
ListNode * headbig = big;
ListNode * headsmall =small;
//
while (pro != nullptr) {
//大于时放到 big 链表上
if (pro->val >= x) {
big->next = pro;
big = big->next;
// 小于放到 small 链表上
}else {
small->next = pro;
small = small->next;
}
pro = pro->next;
}
//细节
big->next = nullptr;
//
small->next = headbig->next;
return headsmall->next;
}
};
```

View File

@ -34,6 +34,12 @@
是不是很容易理解下面我们来看代码吧
**题目代码**
Java Code:
```java
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
@ -79,3 +85,47 @@ class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
ListNode * temp = new ListNode(-1);
temp->next = head;
ListNode * pro = temp;
//来到 left 节点前的一个节点
int i = 0;
for (; i < left-1; ++i) {
pro = pro->next;
}
// 保存 left 节点前的第一个节点
ListNode * leftNode = pro;
for (; i < right; ++i) {
pro = pro->next;
}
// 保存 right 节点后的节点
ListNode * rightNode = pro->next;
//切断链表
pro->next = nullptr;
ListNode * newhead = leftNode->next;
leftNode->next = nullptr;
leftNode->next = rever(newhead);
//重新接头
newhead->next = rightNode;
return temp->next;
}
ListNode * rever (ListNode * head) {
ListNode * low = nullptr;
ListNode * pro = head;
while (pro != nullptr) {
ListNode * temp = pro;
pro = pro->next;
temp->next = low;
low = temp;
}
return low;
}
};
```

View File

@ -26,14 +26,18 @@
### HashSet
这个方法是比较简单的主要思路就是先遍历一个链表将链表的所有值都存到哈希表中然后再遍历另一个链表如果发现某个结点在哈希表中已经存在那我们直接返回该节点即可代码也很简单
这个方法是比较简单的主要思路就是先遍历一个链表将链表的所有值都存到Hashset中然后再遍历另一个链表如果发现某个结点在Hashset中已经存在那我们直接返回该节点即可代码也很简单
**题目代码**
Java Code
```java
public class Solution {
public ListNode getIntersectionNode (ListNode headA, ListNode headB) {
ListNode tempa = headA;
ListNode tempb = headB;
//定义hash表
//定义Hashset
HashSet<ListNode> arr = new HashSet<ListNode>();
while (tempa != null) {
arr.add(tempa);
@ -45,12 +49,36 @@ public class Solution {
}
tempb = tempb.next;
}
return tempb;
return tempb;
}
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * tempa = headA;
ListNode * tempb = headB;
//定义Hashset, cpp对应set
set <ListNode *> arr;
while (tempa != nullptr) {
arr.insert(tempa);
tempa = tempa->next;
}
while (tempb != nullptr) {
if (arr.find(tempb) != arr.end()) {
return tempb;
}
tempb = tempb->next;
}
return tempb;
}
};
```
下面这个方法比较巧妙不是特别容易想到大家可以自己实现一下这个方法也是利用我们的双指针思想
下面我们直接看动图吧特别直观一下就可以搞懂
@ -59,6 +87,10 @@ public class Solution {
是不是一下就懂了呀我们利用双指针当某一指针遍历完链表之后然后掉头去另一个链表的头部继续遍历因为速度相同所以他们第二次遍历的时候肯定会相遇是不是很浪漫啊
**题目代码**
Java Code
```java
public class Solution {
public ListNode getIntersectionNode (ListNode headA, ListNode headB) {
@ -76,7 +108,25 @@ public class Solution {
}
```
C++ Code
```cpp
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
//定义两个节点
ListNode * tempa = headA;
ListNode * tempb = headB;
//循环
while (tempa != tempb) {
//如果不为空就指针下移为空就跳到另一链表的头部
tempa = tempa != nullptr ? tempa->next: headB;
tempb = tempb != nullptr ? tempb->next: headA;
}
return tempa;
}
};
```
好啦链表的题目就结束啦希望大家能有所收获下周就要更新新的题型啦继续坚持肯定会有收获的

View File

@ -27,8 +27,13 @@
![合并数组](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/photo/合并数组.216f4nn4lti8.gif)
**题目代码**
Java Code:
```java
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode headpro = new ListNode(-1);
ListNode headtemp = headpro;
while (l1 != null && l2 != null) {
@ -45,7 +50,33 @@
}
headpro.next = l1 != null ? l1:l2;
return headtemp.next;
}
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode * headpro = new ListNode(-1);
ListNode * headtemp = headpro;
while (l1 != nullptr && l2 != nullptr) {
//接上大的那个
if (l1->val >= l2->val) {
headpro->next = l2;
l2 = l2->next;
}
else {
headpro->next = l1;
l1 = l1->next;
}
headpro = headpro->next;
}
headpro->next = l1 != nullptr ? l1: l2;
return headtemp->next;
}
};
```

View File

@ -26,14 +26,20 @@
### HashSet
这个方法是比较简单的主要思路就是先遍历一个链表将链表的所有值都存到哈希表中然后再遍历另一个链表如果发现某个结点在哈希表中已经存在那我们直接返回该节点即可代码也很简单
这个方法是比较简单的主要思路就是先遍历一个链表将链表的所有值都存到Hashset中然后再遍历另一个链表如果发现某个结点在Hashset中已经存在那我们直接返回该节点即可代码也很简单
**题目代码**
Java Code:
```java
public class Solution {
public ListNode getIntersectionNode (ListNode headA, ListNode headB) {
ListNode tempa = headA;
ListNode tempb = headB;
//定义hash表
//定义Hashset
HashSet<ListNode> arr = new HashSet<ListNode>();
while (tempa != null) {
arr.add(tempa);
@ -51,6 +57,31 @@ public class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode * getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * tempa = headA;
ListNode * tempb = headB;
//定义Hashset
set <ListNode *> arr;
while (tempa != nullptr) {
arr.insert(tempa);
tempa = tempa->next;
}
while (tempb != nullptr) {
if (arr.find(tempb) != arr.end()) {
return tempb;
}
tempb = tempb->next;
}
return tempb;
}
};
```
下面这个方法比较巧妙不是特别容易想到大家可以自己实现一下这个方法也是利用我们的双指针思想
下面我们直接看动图吧特别直观一下就可以搞懂
@ -59,6 +90,12 @@ public class Solution {
是不是一下就懂了呀我们利用双指针当某一指针遍历完链表之后然后掉头去另一个链表的头部继续遍历因为速度相同所以他们第二次遍历的时候肯定会相遇是不是很浪漫啊
**题目代码**
Java Code:
```java
public class Solution {
public ListNode getIntersectionNode (ListNode headA, ListNode headB) {
@ -68,15 +105,33 @@ public class Solution {
//循环
while (tempa != tempb) {
//如果不为空就指针下移为空就跳到另一链表的头部
tempa = tempa!=null ? tempa.next:headB;
tempb = tempb!=null ? tempb.next:headA;
tempa = tempa != null ? tempa.next: headB;
tempb = tempb != null ? tempb.next: headA;
}
return tempa;
}
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode * getIntersectionNode(ListNode *headA, ListNode *headB) {
//定义两个节点
ListNode * tempa = headA;
ListNode * tempb = headB;
//循环
while (tempa != tempb) {
//如果不为空就指针下移为空就跳到另一链表的头部
tempa = tempa != nullptr ? tempa->next: headB;
tempb = tempb != nullptr ? tempb->next: headA;
}
return tempa;
}
};
```
好啦链表的题目就结束啦希望大家能有所收获下周就要更新新的题型啦继续坚持肯定会有收获的

View File

@ -30,6 +30,10 @@
感觉这个方法既巧妙又简单大家可以自己动手打一下这个题目是经典题目
**题目代码**
Java Code:
```java
class Solution {
public ListNode getKthFromEnd (ListNode head, int k) {
@ -58,3 +62,34 @@ class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode * getKthFromEnd(ListNode * head, int k) {
//特殊情况
if (head == nullptr) {
return head;
}
//初始化两个指针
ListNode * pro = new ListNode(-1);
ListNode * after = new ListNode(-1);
//定义指针指向
pro = head;
after = head;
//先移动绿指针到指定位置
for (int i = 0; i < k-1; i++) {
pro = pro->next;
}
//两个指针同时移动
while (pro->next != nullptr) {
pro = pro->next;
after = after->next;
}
//返回倒数第k个节点
return after;
}
};
```

View File

@ -48,6 +48,10 @@
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210321131249789.gif)
**题目代码**
Java Code:
```java
class Solution {
public ListNode middleNode(ListNode head) {
@ -64,3 +68,21 @@ class Solution {
}
```
C++ Code:
```cpp
public:
ListNode* middleNode(ListNode* head) {
ListNode * fast = head;//快指针
ListNode * slow = head;//慢指针
//循环条件思考一下跳出循环的情况
while (fast != nullptr && fast->next != nullptr) {
fast = fast->next->next;
slow = slow->next;
}
//返回slow指针指向的节点
return slow;
}
};
```

View File

@ -69,6 +69,12 @@
这里需要注意得时链表遍历结束我们应该跳出循环但是我们的nlist仍在尾部添加了1节点那是因为跳出循环时summod值为1所以我们需要在尾部再添加一个节点
**题目代码**
Java Code:
```java
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
@ -108,3 +114,45 @@ class Solution {
}
```
C++ Code:
```cpp
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
//返回链表
ListNode * nList = new ListNode(-1);
ListNode * tempnode = nList;
//用来保存进位值初始化为0
int summod = 0;
while(l1 != nullptr || l2 != nullptr) {
//如果l1的链表为空则l1num为0若是不为空则为链表的节点值
//判断是否为空为空就设为0
int l1num = l1 == nullptr ? 0 : l1->val;
int l2num = l2 == nullptr ? 0 : l2->val;
//将链表的值和进位值相加得到为返回链表的值
int sum = l1num + l2num + summod;
//更新进位值例18/10=19/10=0
summod = sum / 10;
//新节点保存的值18 % 8=2则添加2
sum = sum % 10;
//添加节点
tempnode->next = new ListNode(sum);
//移动指针
tempnode = tempnode->next;
if (l1 != nullptr) {
l1 = l1->next;
}
if (l2 != nullptr) {
l2 = l2->next;
}
}
//最后根据进位值判断需不需要继续添加节点
if (summod == 1) {
tempnode->next = new ListNode(summod);
}
return nList->next;
}
};
```