你有两个用链表代表的整数,其中每个节点包含一个数字。数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头。写出一个函数将两个整数相加,用链表形式返回和。
样例
样例 1:
输入: 7->1->6->null, 5->9->2->null
输出: 2->1->9->null
样例解释: 617 + 295 = 912, 912 转换成链表: 2->1->9->null
样例 2:
输入: 3->1->5->null, 5->9->2->null
输出: 8->0->8->null
样例解释: 513 + 295 = 808, 808 转换成链表: 8->0->8->null
对题目理解不好,数据类型换成long 解答:通过70%
class Solution {
public:
/**
* @param l1: the first list
* @param l2: the second list
* @return: the sum list of l1 and l2
*/
ListNode * addLists(ListNode * l1, ListNode * l2) {
// write your code here
stack<int> res1,res2;
if(l1==NULL ){
return l2;
}
if(l2==NULL){
return l1;
}
while(l1!=NULL){
res1.push(l1->val);
l1=l1->next;
}
while(l2!=NULL){
res2.push(l2->val);
l2=l2->next;
}
int len1=res1.size();
int len2=res2.size();
int num1 = 0;
while(len1--){
int temp1=res1.top()*pow(10,len1);
res1.pop();
num1 = num1+temp1;
}
int num2 = 0;
while(len2--){
int temp2=res2.top()*pow(10,len2);
res2.pop();
num2 = num2+temp2;
}
int num = num1+num2;
cout<<num<<endl;
vector<int> result;
while(num>=10){
int temp = num%10;
result.push_back(temp);
num=num/10;
}
result.push_back(num);
int l = result.size();
cout<<l<<endl;
ListNode* head = new ListNode(result[0]);
ListNode * temp =head;
for(int i=1;i<l;i++){
ListNode* node = new ListNode(result[i]);
cout<<node->val<<endl;
temp->next=node;
temp = node;
}
return head;
}
};
优秀解法:
/**
* Definition of singly-linked-list:
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param l1: the first list
* @param l2: the second list
* @return: the sum list of l1 and l2
*/
ListNode *addLists(ListNode *l1, ListNode *l2) {
// write your code here
ListNode *head = new ListNode(0);
ListNode *end = head;
ListNode *curr1 = l1;
ListNode *curr2 = l2;
int carry = 0;
// 深入理解题目,求和进位进到后面去了,所以从前往后遍历就行
while (curr1 != nullptr || curr2 != nullptr || carry != 0)
{
int a1 = 0;
int a2 = 0;
if (curr1 != nullptr)
{
a1 = curr1->val;
curr1 = curr1->next;
}
if (curr2 != nullptr)
{
a2 = curr2->val;
curr2 = curr2->next;
}
int sum = a1 + a2 + carry;
carry = sum / 10;
sum %= 10;
ListNode *curr = new ListNode(sum);
end->next = curr;
end = curr;
}
return head->next;
}
};
165. 合并两个排序链表
将两个排序链表合并为一个新的排序链表
样例
样例 1:
输入: list1 = null, list2 = 0->3->3->null
输出: 0->3->3->null
样例2:
输入: list1 = 1->3->8->11->15->null, list2 = 2->null
输出: 1->2->3->8->11->15->null
/**
* Definition of singly-linked-list:
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param l1: ListNode l1 is the head of the linked list
* @param l2: ListNode l2 is the head of the linked list
* @return: ListNode head of linked list
*/
ListNode * mergeTwoLists(ListNode * l1, ListNode * l2) {
// write your code here
if(l1 ==NULL){
return l2;
}
if(l2== NULL){
return l1;
}
ListNode * head= NULL;
if(l1->val >= l2->val){
head=l2;
head->next = mergeTwoLists(l1,l2->next);
}
else{
head=l1;
head->next = mergeTwoLists(l1->next,l2);
}
return head;
}
};
翻转链表:
/**
* Definition of singly-linked-list:
*
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: n
* @return: The new head of reversed linked list.
*/
ListNode * reverse(ListNode * head) {
// write your code here
if(head == NULL || head->next == NULL){
return head;
}
ListNode * head_new = NULL;
ListNode * cur = head;
while(cur!=NULL){
ListNode * temp = cur;
cur = cur->next;
ListNode * head_pre= head_new;
head_new =temp;
head_new->next = head_pre;
head_new->val=temp->val;
}
return head_new;
}
};
// 找到单链表倒数第n个节点,保证链表中节点的最少数量为n。
// 样例
// Example 1:
// Input: list = 3->2->1->5->null, n = 2
// Output: 1
// 当语言有问题时,可以重置一下
class Solution {
public:
/*
* @param head: The first node of linked list.
* @param n: An integer
* @return: Nth to last node of a singly linked list.
*/
ListNode * nthToLast(ListNode * head, int n) {
// write your code here
// 双指针问题解决
if(head==NULL || n<=0 ){
return NULL;
}
ListNode *fast=head;
ListNode *slow=head;
while(n--){
fast = fast->next;
}
while(fast!=NULL){
fast = fast->next;
slow = slow->next;
}
return slow;
}
};
102. 带环链表
给定一个链表,判断它是否有环。
样例
```
样例 1:
输入: 21->10->4->5, then tail connects to node index 1(value 10).
输出: true
样例 2:
输入: 21->10->4->5->null
输出: false
```
挑战
不要使用额外的空间
/**
* Definition of singly-linked-list:
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: The first node of linked list.
* @return: True if it has a cycle, or false
*/
bool hasCycle(ListNode * head) {
// write your code here
if(head==NULL || head->next==NULL){
return false;
}
ListNode* slow = head;
ListNode* fast = head;
// 注意,这里要避免野指针出现,判断快指针是否到头即可
while(fast !=NULL && fast->next !=NULL){
slow = slow->next;
fast = fast->next->next;
if(slow == fast){
return true;
}
}
return false;
}
};
给出一个所有元素以升序排序的单链表,将它转换成一棵高度平衡的二叉搜索树
样例
样例 1:
输入: array = 1->2->3
输出:
2
/
1 3
样例 2:
输入: 2->3->6->7
输出:
3
/
2 6
7
解释:
可能会有多个符合要求的结果,返回任意一个即可。
/**
* Definition of ListNode
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
* Definition of TreeNode:
* class TreeNode {
* public:
* int val;
* TreeNode *left, *right;
* TreeNode(int val) {
* this->val = val;
* this->left = this->right = NULL;
* }
* }
*/
// class Solution {
// public:
// /*
// * @param head: The first node of linked list.
// * @return: a tree node
// */
// TreeNode * sortedListToBST(ListNode * head) {
// // write your code here
// if(head==NULL){
// return NULL;
// }
// if(head->next==NULL){
// TreeNode* t_node=new TreeNode(head->val);
// return t_node;
// }
// if(head->next->next==NULL){
// TreeNode* t_node=new TreeNode(head->val);
// t_node->right = new TreeNode(head->next->val);
// return t_node;
// }
// int len = 0;
// ListNode * temp = head;
// while(temp){
// len++;
// temp = temp->next;
// }
// int mid = len/2;
// ListNode * mid_node = head;
// while(mid--){
// mid_node = mid_node->next;
// }
// ListNode * mid_next = mid_node->next;
// mid_node->next == NULL;
// TreeNode* root = new TreeNode(mid_node->val);
// root->left = sortedListToBST(head);
// root->right = sortedListToBST(mid_next);
// return root;
// }
// };
class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
vector<int> v;
ListNode* cur=head;
while(cur!=NULL){
v.push_back(cur->val);
cur=cur->next;
}
TreeNode* root=buildBST(v,0,v.size()-1);
return root;
}
TreeNode* buildBST(vector<int>& nums,int l,int r){
if(l>r) return NULL;
int mid=(l+r)/2;
auto node= new TreeNode(nums[mid]);
node->left=buildBST(nums,l,mid-1);
node->right=buildBST(nums,mid+1,r);
return node;
}
};
剑指 Offer 52. 两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出: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 个节点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if(headA==NULL || headB==NULL){
return NULL;
}
ListNode *A = headA;
int lenA=0;
ListNode *B = headB;
int lenB=0;
while(A!=NULL){
lenA++;
A=A->next;
}
while(B!=NULL){
lenB++;
B=B->next;
}
int step= 0;
ListNode *tempA=headA;
ListNode *tempB=headB;
if(lenA>lenB){
step= lenA-lenB;
while(step){
tempA=tempA->next;
step--;
}
while(tempA!=NULL&&tempB!=NULL){
if(tempA==tempB){
return tempA;
}
tempA=tempA->next;
tempB=tempB->next;
}
}else{
step= lenB-lenA;
while(step){
tempB=tempB->next;
step--;
}
while(tempA!=NULL&&tempB!=NULL){
if(tempA==tempB){
return tempA;
}
tempA=tempA->next;
tempB=tempB->next;
}
}
return NULL;
}
};
思路:快慢指针
遍历两个链表,然后计算两个链表的节点数量,计算两个链表的节点数量差;
然后重新开始遍历,节点多的链表先开始,走多出来的节点个步数,然后节点少的链表和节点多的链表同时开始遍历,当指向的位置相同时,即为第一个交点;
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1->4->5, 1->3->4, 2->6 ] 将它们合并到一个有序链表中得到。 1->1->2->3->4->4->5->6
示例 2:
输入:lists = [] 输出:[]
示例 3:
输入:lists = [[]] 输出:[]
提示:
k == lists.length0 <= k <= 10^40 <= lists[i].length <= 500-10^4 <= lists[i][j] <= 10^4lists[i]按 升序 排列lists[i].length的总和不超过10^4
两种思路:
1)使用优先队列的方法,每个链表取一个元素放入优先队列,每次从优先队列里取最小的那个元素
2)归并排序的思想,有序链表两两合并
https://blog.csdn.net/aikudexue/article/details/90769813
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, compare> q;
for (auto l : lists) {
if (l) {
q.push(l); //每个链表取一个元素放入优先队列
}
}
ListNode pre(0); //新建一个头结点,可以防止丢失最终链表的头
ListNode *node = &pre
while (q.size()) {
ListNode *top = q.top(); //从优先队列里取最小的那个元素
q.pop();
node->next = top; //将弹出的那个元素连到最终链表上
node = node->next; //指针向后移一步
if (top->next) {
q.push(top->next); //将下一个元素入队列
}
}
return pre.next;
}
struct compare {
bool operator()(const ListNode* l1, const ListNode* l2) {
return l1->val > l2->val;
}
};
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
// class Solution {
// public:
// ListNode* mergeKLists(vector<ListNode*>& lists) {
// priority_queue<ListNode*, vector<ListNode*>, compare> q;
// for (auto l : lists) {
// if (l) {
// q.push(l); //每个链表取一个元素放入优先队列
// }
// }
// ListNode pre(0); //新建一个头结点,可以防止丢失最终链表的头
// ListNode *node = ⪯
// while (q.size()) {
// ListNode *top = q.top(); //从优先队列里取最小的那个元素
// q.pop();
// node->next = top; //将弹出的那个元素连到最终链表上
// node = node->next; //指针向后移一步
// if (top->next) {
// q.push(top->next); //将下一个元素入队列
// }
// }
// return pre.next;
// }
// struct compare {
// bool operator()(const ListNode* l1, const ListNode* l2) {
// return l1->val > l2->val;
// }
// };
// };
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
return partition(lists, 0, lists.size()-1); //合并0-(size-1)的链表
}
ListNode* partition(vector<ListNode*>& lists, int start, int end){
if(start == end){
return lists[start];
}
if(start < end){
int mid = (end+start)/2;
ListNode* l1 = partition(lists, start, mid); //合并start->mid的链表
ListNode* l2 = partition(lists, mid+1, end); //合并mid+1到end的链表
//partition最终递归到最后还是两个链表的合并.举个例子来说比如合并6个链表,那么按照分治法,我们首先分别合并1和4,2和5,3和6。这样下一次只需合并3个链表,我们再合并1和3,最后和2合并就可以了。
return merge(l1, l2);
}
return NULL;
}
ListNode* merge(ListNode* l1, ListNode* l2){ //合并L1,L2两个有序链表
if(!l1) return l2;
if(!l2) return l1;
if(l1->val < l2->val){
l1->next = merge(l1->next, l2);
return l1;
}else{
l2->next = merge(l1, l2->next);
return l2;
}
}
};
重新写的思路:
1)先合并两个
2)然后两两合并
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *newHead=new ListNode(0);
ListNode *head=newHead;
while(l1!=NULL&&l2!=NULL){
if(l1->val>l2->val){
newHead->next=l2;
l2=l2->next;
newHead=newHead->next;
}else{
newHead->next=l1;
l1=l1->next;
newHead=newHead->next;
}
}
if(l1!=NULL&&l2==NULL){
newHead->next=l1;
}else if(l1==NULL&&l2!=NULL){
newHead->next=l2;
}
return head->next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
if(lists.size()==0){
return NULL;
}
int interval =1;
int len = lists.size();
while(interval<len){
for(int i=0;i<len-interval;){
lists[i]=mergeTwoLists(lists[i],lists[i+1]);
i=i+interval*2;
}
interval = interval*2;
}
return lists[0];
}
};
19. 删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
思路:快慢指针实现,但需要注意链表中删除头节点的情况特殊处理;
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
// 双指针问题解决
if(head==NULL || n<=0 ){
return NULL;
}
if(head->next==NULL){
return NULL;
}
ListNode *fast=head;
ListNode *slow=head;
while(n--){
fast = fast->next;
}
ListNode * temp = NULL;
while(fast!=NULL){
fast = fast->next;
temp = slow;
slow = slow->next;
}
if(slow==head){
ListNode * head_new = slow->next;
slow->next = NULL;
return head_new;
}
else{
temp->next= slow->next;
slow->next=NULL;
}
return head;
}
};
83. 删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3
思路:很简单,遍历链表,因为链表有序,依次比较当前元素和下一个元素是否相等,相等则删除下一个元素,将链表指针重新指向;
递归这个过程,直到链表结束,一次AC
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head==NULL||head->next==NULL){
return head;
}
ListNode* cur = head;
while(cur->next!=NULL){
if(cur->val==cur->next->val){
cur->next=cur->next->next;
deleteDuplicates(head);
}
else{
cur=cur->next;
}
}
return head;
}
};
61. 旋转链表
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
解题思路:
step1:将链表首位相连成环;
step2:在k = list_len - k % list_len处断开。
如果理解起来比较抽象,可以画个图帮助理解,找到断开点以及返回新的头节点;
注意链表遍历cur和cur2不要用错,--k 还是 k--要验证清楚
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(head==NULL){
return head;
}
ListNode* cur = head;
ListNode* cur2 = head;
int len = 1;
while(cur->next!=NULL){
cur= cur->next;
len++;
}
cur->next = head;
k = len-k%len;
while(--k){
cur2=cur2->next;
}
ListNode* head_new = cur2->next;
cur2->next=NULL;
return head_new;
}
};
思路参考:https://blog.csdn.net/starzyh/article/details/90345257
138. 复制带随机指针的链表
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的 深拷贝。
我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
思路:
第一次遍历链表的时候,复制旧链表的节点值建立一个新的链表,同时定义一个 unordered_map 作为哈希表,哈希表的键为旧链表的节点指针,值为新链表的节点指针。
然后,第二次遍历链表,访问旧链表节点的随机指针,然后以此为键从 map 中取出对应的新链表节点指针,这也就是当前新链表节点的随机指针。
https://www.cnblogs.com/seniusen/p/10142869.html
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
class Solution {
public:
Node *copyRandomList(Node *head) {
unordered_map<Node *, Node *> nodemap;
Node *temp = head;
Node *new_head = new Node(0); //哨兵节点,方便操作
Node *copy_temp = new_head;
// 建立新链表
while (temp)
{
copy_temp->next = new Node(temp->val);
nodemap[temp] = copy_temp->next;
temp = temp->next;
copy_temp = copy_temp->next;
}
Node *random_temp = NULL;
temp = head;
copy_temp = new_head->next;
// 填充新链表的随机指针
while (temp)
{
random_temp = temp->random;
if (random_temp != NULL) copy_temp->random = nodemap[random_temp];
else
copy_temp->random = NULL;
temp = temp->next;
copy_temp = copy_temp->next;
}
return new_head->next;
}
};
876. 链表的中间结点
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
思路:快慢指针,注意奇数个节点和偶数个节点,设置一个标志未来处理
1--2--3--4--5
1--2--3--4
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
if(head ->next == NULL){
return head;
}
if(head->next->next==NULL){
return head->next;
}
ListNode* slow = head;
ListNode* fast =head;
int flag =1;
while(fast->next!=NULL&&fast->next->next!=NULL){
fast = fast->next->next;
slow = slow->next;
}
if(fast->next!=NULL){
flag=0;
}
if(flag==0){
return slow->next;
}
return slow;
}
};