160.相交链表
题目
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
。
图示两个链表在节点 c1
开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
-
intersectVal
- 相交的起始节点的值。如果不存在相交节点,这一值为0
-
listA
- 第一个链表 -
listB
- 第二个链表 -
skipA
- 在listA
中(从头节点开始)跳到交叉节点的节点数 -
skipB
- 在listB
中(从头节点开始)跳到交叉节点的节点数
评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA
和 headB
传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
思路
直接模拟,得到两个链表长度后让长的先走完两者差值然后再一起遍历,当两者相等时停下
代码如下:
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* targetA = headA;
ListNode* targetB = headB;
int lengthA = 0,lengthB = 0;
while(targetA || targetB){
if(targetA){
lengthA++;
targetA = targetA->next;
}
if(targetB){
lengthB++;
targetB = targetB->next;
}
}
if( lengthA > lengthB ){
int len = lengthA-lengthB;
while(len--){
headA = headA->next;
}
}
else{
int len = lengthB-lengthA;
while(len--){
headB = headB->next;
}
}
while(headA != headB && headA && headB){
headA = headA->next;
headB = headB->next;
}
if(headA == headB)return headA;
else return NULL;
}
};
206.反转链表
题目
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[]
思路
设两个指针,然后调换一次,更新一次,一直到末尾,(这个反转还好,后面有个题k组反转更难)
代码如下:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* first = NULL;
ListNode* second = head;
while(second){
ListNode* tmp = second->next;
second->next = first;
first = second;
second = tmp;
}
return first;
}
};
234.回文链表
题目
给你一个单链表的头节点 head
,请你判断该链表是否为
回文链表
。如果是,返回 true
;否则,返回 false
。
示例 1:
输入:head = [1,2,2,1] 输出:true
示例 2:
输入:head = [1,2] 输出:false
思路
遍历一次存到数组里面,然后用数组判断即可
代码如下:
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> a;
ListNode* tr = head;
while(tr){
a.emplace_back(tr->val);
tr = tr->next;
}
for(int i = 0;i < a.size()/2;i++){
if(a[i] != a[a.size()-1-i])return false;
}
return true;
}
};
141.环形链表
题目
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
思路
快慢指针,若是有环的话一定会相等的,不过有道题是环形链表II比这个难,那个需要判断环的入口,也是设快慢指针,设相等时两者走的路程为f和s,有f = 2*s同时f肯定比s多走了n圈环,假设环的长度为b,环之前长度
为a,a+nb一定到环入口,所以快慢指针相遇后,把其中一个移到开头,共同走a后一定会到环入口,也就是比这道题更难一点的了。
代码如下:
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL || head->next == NULL) return false;
ListNode* fast = head->next->next;
ListNode* slow = head->next;
while(fast != slow && fast && fast->next){
fast = fast->next->next;
slow = slow->next;
}
if(!fast || !fast->next) return false;
return true;
}
};
142.环形链表II
题目
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。
思路
上面一题提到了思路,代码如下:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head == NULL || head->next == NULL)return NULL;
ListNode* fast = head;
ListNode* slow = head;
while(1){
if(fast == NULL || fast->next == NULL)return NULL;
fast = fast->next->next;
slow = slow->next;
if(fast == slow) break;
}
slow = head;
while(fast != slow){
fast = fast->next;
slow = slow->next;
}
return fast;
}
};
21.合并两个有序链表
题目
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
思路
直接模拟,每次都取两者小的同时next,最后某个为空后直接接上另一个不为空的节点即可
代码如下:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* boom=new ListNode();
ListNode* cur=boom;
while(list1&&list2){
if(list1->val<list2->val){
cur->next=list1;
list1=list1->next;
}
else{
cur->next=list2;
list2=list2->next;
}
cur=cur->next;
}
cur->next=list1?list1:list2;
return boom->next;
}
};
2.两数相加
题目
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0] 输出:[0]
思路
维护一个进位值add,一开始l1+l2+add,更新add = (l1+l2+add)/10;和本位node = (l1+l2+add)%10;当其中一个为空后,假设是l1为空,则更新add = (l2+add)/10;和本位node = (l2+add)%10,最后若是add仍不为空,则补一个高位1接后面去(加法进位只可能是1)
代码如下:
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* ans = new ListNode();
ListNode* cur = ans;
int add = 0;
while(l1 && l2){
int res = (l1->val + l2->val + add)%10;
add = (l1->val + l2->val + add) / 10;
ListNode* node = new ListNode(res);
cur->next = node;
cur = cur->next;
l1 = l1->next;
l2 = l2->next;
}
if(l1){
while(l1){
int res = (l1->val+add)%10;
add = (l1->val+add)/10;
ListNode* node = new ListNode(res);
cur->next = node;
cur = cur->next;
l1 = l1->next;
}
}
else{
while(l2){
int res = (l2->val+add)%10;
add = (l2->val+add)/10;
ListNode* node = new ListNode(res);
cur->next = node;
cur = cur->next;
l2 = l2->next;
}
}
if(add != 0){
ListNode* node = new ListNode(add);
cur->next = node;
}
return ans->next;
}
};