leetcode刷题链表-第1刷
Posted 非晚非晚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode刷题链表-第1刷相关的知识,希望对你有一定的参考价值。
为了提高自己理解算法和编程的能力,在这里会时不时的刷一下LeetCode的题目,每一期十道题。坚持就是胜利,希望自己能够一直坚持把题目刷下去,加油!
1. 两数相加
题目:给你两个
非空
的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储 一位 数字。
解题思路:加法运算,主要考察链表的熟悉程度
/**
* 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* addTwoNumbers(ListNode* l1, ListNode* l2) {
//先算一个加法
ListNode* head = new ListNode( (l1->val + l2->val) % 10 );
ListNode* tail = head;
int flag = (l1->val + l2->val) / 10;
l1 = l1->next;
l2 = l2->next;
while(l1 != nullptr || l2 != nullptr)
{
ListNode* tmp = new ListNode;
if(l1 !=nullptr && l2 != nullptr)//都不为零
{
tmp->val = (l1->val + l2->val + flag) % 10 ;
flag = (l1->val + l2->val + flag) / 10;
l1 = l1->next;
l2 = l2->next;
}
else if(l1 != nullptr)//l2为零
{
tmp->val = (l1->val + flag) % 10 ;
flag = (l1->val + flag) / 10;
l1 = l1->next;
}
else //l1为零
{
tmp->val = (l2->val + flag) % 10 ;
flag = (l2->val + flag) / 10;
l2 = l2->next;
}
tail->next = tmp;
tail = tail->next;
}
if(flag == 1) //结尾判断是否有进位
{
ListNode* tmp = new ListNode(1);
tail->next = tmp;
tail = tail->next;
}
tail->next = nullptr;//最后指向nullprt
return head;
}
};
2. 删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
解题思路:定义两个指针,一个快指针,一个慢指针,快指针先走n步。因为size = n + x;其中对于同一个元素,n为倒着数(从1开始),x为顺着数(从0开始)的位置。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(!head | !head -> next) return NULL;
ListNode * fast = head, *slow = head;
//快指针先走n步
for(int i = 0; i < n; i++){
fast = fast -> next;
}
if(!fast){
return head -> next;
}
//快慢指针一起
while(fast -> next){
fast = fast -> next;
slow = slow -> next;
}
slow -> next = slow -> next -> next;
return head;
}
};
3. 合并两个有序链表
题目:将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
解题思路:新建链表,并分别用head和tail指针指向头部和尾部,然后依次遍历就可以了。(使用了一个空的head,也就是val为0的head)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
// 使用带头结点的链表解决问题
// 待输出链表的头部
ListNode * head = new ListNode();//新建的head不用
// 待输出链表的 tail 结点
ListNode * tail = head;
while(l1 != nullptr && l2 != nullptr) {
if(l1->val > l2->val) {
tail->next = l2;
l2 = l2->next;
}else{
tail->next = l1;
l1 = l1->next;
}
tail = tail->next;
}
// l1 或 l2 可能还有剩余结点没有合并,
// 由于从上面的 while 循环中退出, 那么链表 l1 和 l2 至少有一个已经遍历结束
if(l1 != nullptr) tail->next = l1;
if(l2 != nullptr) tail->next = l2;
return head->next;
}
};
4. 合并K个升序链表
题目:给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。
解题思路:和第3题是一样的,只不过多添加了一个循环而已。
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
{
ListNode* head = new ListNode();//头节点
ListNode* tail = head;
while(l1 && l2){//两个序列都不为0
if(l1->val > l2->val){
tail->next = l2;
tail = tail->next;
l2 = l2->next;
}else{
tail->next = l1;
tail = tail->next;
l1 = l1->next;
}
}
if(l1) tail ->next = l1;//l1不为空
if(l2) tail->next = l2;//l2不为空
return head->next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode* head = nullptr;//头节点
for(int i = 0; i < lists.size(); i++)
head = mergeTwoLists(head, lists[i]);//合并两个
return head;
}
};
5. 两两交换链表中的节点
题目:给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。你不能只是单纯的改变节点内部的值,
而是需要实际的进行节点交换
。
解题思路:主要考察交换节点,注意节点的前面的链接和后面的链接问题。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);//开辟一个为0的节点
dummyHead->next = head;
ListNode* temp = dummyHead;//temp为记录前链接
while (temp->next != nullptr && temp->next->next != nullptr) {
ListNode* node1 = temp->next;//待交换的第一个节点
ListNode* node2 = temp->next->next;//带交换的第二个节点
temp->next = node2;//前链接
node1->next = node2->next;//后连接
node2->next = node1;//交换
temp = node1;//往前移
}
return dummyHead->next;
}
};
6. 旋转链表
题目:给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
解题思路:其实就是把末尾的k个链表挪到前面,先计算链表元素的个数,防止k过大,需要取余,然后设计
环形链表
,最后设置nullptr指针就可以了。(当然也可以用快慢指针,不过计算比这个稍微复杂)
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (k == 0 || head == nullptr || head->next == nullptr) {
return head;
}
int n = 1;
ListNode* iter = head;
while (iter->next != nullptr) {//计算元素个数
iter = iter->next;
n++;
}
int add = n - k % n;
if (add == n) {
return head;
}
iter->next = head;//形成环形链表
while (add--) {//找末尾节点
iter = iter->next;
}
ListNode* ret = iter->next;//头结点
iter->next = nullptr;//末尾节点断开
return ret;
}
};
7. 删除排序链表中的重复元素
题目:存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除所有重复的元素,
使每个元素只出现一次
。返回同样按升序排列的结果链表。
解题思路:把重复链表的第一个指向下一个就可以了,还是比较简单的一提。
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr || head->next == nullptr) return head;
ListNode* post = nullptr;
ListNode* tmp = head;
while(tmp->next != nullptr)
{
post = tmp->next;
if(tmp->val == post->val)//如果相等
{
tmp->next = post->next;
}
else//如果不相等
{
tmp = tmp->next;
}
}
return head;
}
};
8. 删除排序链表中的重复元素 II
题目:存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,
只保留原始链表中没有重复
出现的数字。返回同样按升序排列的结果链表。
解体思路:保留前向节点,然后依次比较key和tmp节点,key为不动的待比较节点,tmp为移动带比较节点。
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == nullptr || head->next == nullptr) return head;
ListNode * dummyHead = new ListNode();
dummyHead->next = head;
ListNode* pre = dummyHead;//保留前向节点
ListNode* key = dummyHead->next;//待比较节点
ListNode* tmp = key->next;//移动的带比较节点
while(tmp != nullptr)
{
if(key->val == tmp->val)//相同元素
{
tmp = tmp->next;
}
else if(key->next == tmp)//不同元素,且相邻
{
pre->next = key;
pre = key;
key = key->next;
tmp = tmp->next;
}
else//不同元素,且不相邻
{
key = tmp;
tmp = key->next;
}
}
if(key->next == tmp)// 相邻
{
pre->next = key;
}
else pre->next = nullptr;//最后几位元素相同
return dummyHead->next;
}
};
9. 分隔链表
题目:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。你应当保留 两个分区中每个节点的初始相对位置。
解题思路:建立两个链表,一个小于x的链表和一个大于等于x的链表。然后把两个链表连接起来即可。(可以各新建一个值为0的节点,避免第一次的判断。)
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
if(head == nullptr) return head;
ListNode* tmp = head;
ListNode* biggerHead = nullptr;
ListNode* litterHead = nullptr;
ListNode* tailBiger = biggerHead;
ListNode* tailLitter = litterHead;
while(tmp !=nullptr)
{
if(tmp->val < x)//litter
{
if(tailLitter == nullptr) //如果是第一次
{
litterHead = tmp;
tailLitter = tmp;
}
else
{
tailLitter->next = tmp;
tailLitter = tailLitter->next;
}
}
else//bigger
{
if(tailBiger == nullptr)//如果是第一次
{
biggerHead = tmp;
tailBiger = tmp;
}
else
{
tailBiger->next = tmp;
tailBiger = tailBiger->next;
}
}
tmp = tmp->next;
}
if(biggerHead == nullptr) {tailLitter->next = nullptr;return litterHead;}
else if(litterHead == nullptr) {tailBiger->next = nullptr;return biggerHead;}
else{//两个都不为nullptr
tailLitter->next = biggerHead;
tailBiger->next = nullptr;
return litterHead;
}
}
};
10. 复制带随机指针的链表
解题思路:使用哈希表,key为旧链表,value为新链表。
/*
// 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) {
map<Node*, Node*> m;
m[nullptr] = nullptr;
Node *srcNode = head;
Node *desNode = nullptr;
//构建哈希表
while(srcNode != nullptr){
desNode = new Node(srcNode->val);
m[srcNode] = desNode;
srcNode = srcNode->next;
}
//next和random赋值
srcNode = head;
while(srcNode != nullptr){
m[srcNode]->next = m[srcNode->next];
m[srcNode]->random = m[srcNode->random];
srcNode = srcNode->next;
}
return m[head];
}
};
以上是关于leetcode刷题链表-第1刷的主要内容,如果未能解决你的问题,请参考以下文章