单链表LintCode题目总结(入门-简单)版
链表的实现:
class ListNode {
public:
int val;
ListNode *next;
ListNode(int val)
{
this->val = val;
this->next = NULL;
}
}
225·在链表中找节点(入门)
样例1
输入: 1->2->3 and value = 3
输出: 最后一个结点
样例2
输入: 1->2->3 and value = 4
输出: null
代码实现
ListNode * findNode(ListNode * head, int val) {
// write your code here
ListNode *find=head;
while(find!=NULL)//循环遍历直至空指针
{
if(val==find->val)
{
return find;
}
else
find=find->next;
}
return NULL;
}
228 · 链表的中点(入门)
描述
找链表的中点,并返回这个节点。
样例1:
输入: 1->2->3
输出: 2
样例解释: 返回中间节点
样例2:
输入: 1->2
输出: 1
样例解释: 如果长度是偶数,则返回中间偏左的节点。
代码实现
ListNode * middleNode(ListNode * head)
{
// write your code here
if (head == NULL)
return head;
ListNode *fast=head->next;//快指针,一次遍历两个节点
ListNode *slow=head;//慢指针,一次遍历一个节点,是我们需要返回的值
while(fast!=NULL&&fast->next!=NULL)//当快指针指向空或其下一个表指向空结束循环
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
466 · 链表节点计数(入门)
描述
计算链表中有多少个节点.
样例
样例 1:
输入: 1->3->5->null
输出: 3
样例解释:
返回链表中结点个数,也就是链表的长度.
样例 2:
输入: null
输出: 0
样例解释:
空链表长度为0
代码实现
int countNodes(ListNode * head) {
// write your code here
int ans=0;//计数
while(head!=NULL)
{
head=head->next;
ans++;
}
return ans;
}
483 · 链表转数组(入门)
描述
将一个链表转换为一个数组。
样例
样例 1:
输入: 1->2->3->null
输出: [1,2,3]
样例 2:
输入: 3->5->8->null
输出: [3,5,8]
代码实现
vector<int> toArrayList(ListNode * head) {
// write your code here
vector<int> v1;
ListNode *find=head;
while(find!=NULL)
{
v1.push_back(find->val);
find=find->next;
}
return v1;
}
35 · 翻转链表(一)(简单)
翻转一个链表
链表长度小于 100100
样例
样例 1:
输入:
链表 = 1->2->3->null
输出:
3->2->1->null
样例 2:
输入:
链表 = 1->2->3->4->null
输出:
4->3->2->1->null
代码实现
ListNode * reverse(ListNode * head)
{
// write your code here
ListNode *Newhead=NULL;//记录前一个节点
ListNode *Next=NULL;//用于标记下一个节点
ListNode *Cur=head;//遍历和转向用
while(Cur!=NULL)
{
Next=Cur->next;//记录下一个节点
Cur->next=Newhead;//转向
Newhead=Cur;//后移
Cur=Next;//后移
}
return Newhead;
}
反转链表流程图
96 · 链表划分(简单)
描述
给定一个单链表和数值x,划分链表使得所有小于x的节点排在大于等于x的节点之前。你应该保留两部分内链表节点原有的相对顺序。
样例:
样例 1:
输入:
list = null
x = 0
输出:
null
解释:
空链表本身满足要求
样例 2:
输入:
list = 1->4->3->2->5->2->null
x = 3
输出:
1->2->2->4->3->5->null
解释:
要保持原有的相对顺序。
代码实现
ListNode * partition(ListNode * head, int x) {
ListNode* phead = new ListNode(-1);//建立一个值为-1的头节点
phead->next = head;//指向给定链表
ListNode* pre = phead;//指向-1的节点
ListNode* cur = phead;//指向-1的节点
while(cur->next)//当cur走到最后一个节点出循环
{
if(cur->next->val >= x)//跟给定值比大小
{
cur = cur->next;//大于等于时,后移
}
else if(cur == pre)//当pre和cur指向同一个节点时
{
cur = cur->next;//后移
pre = pre->next;//后移
}
else//出现小于的值时
{
ListNode* temp = cur->next;//记录cur的后一个节点,即记录需要处理的节点
cur->next = temp->next;//指向后一个节点,起到删除temp的作用
temp->next = pre->next;//temp插入到pre后的位置
pre->next = temp;//原pre指向temp;
pre = pre->next;//pre后移一位,即到达temp位;
}
}
return phead->next;
}
链表划分图
112 · 删除排序链表中的重复元素(简单)
描述
给定一个排序链表,删除所有重复的元素,每个元素只留下一个。
样例
样例 1:
输入:
linked list = null
输出:
null
解释:
空链表返回null
样例 2:
输入:
linked list = 1->1->2->null
输出:
1->2->null
解释:
删除重复的1
样例 3:
输入:
linked list = 1->1->2->3->3->null
输出:
1->2->3->null
解释:
删除重复的1和3
代码实现
ListNode * deleteDuplicates(ListNode * head) {
// write your code here
ListNode *find=head;//用来遍历链表
while(find!=NULL&&find->next!=NULL)
{
if(find->next->val==find->val)
{
ListNode *temp=find->next->next;//重复节点之后的节点
delete find->next;//删除重复节点
find->next=temp;//连接链表
}
else
find=find->next;//后移
}
return head;
}
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
代码实现
这里我们使用一个递归函数来实现
ListNode * mergeTwoLists(ListNode * l1, ListNode * l2) {
// write your code here
ListNode *temp;//定义一个暂时的链表
if(l1==NULL&&l2!=NULL)//若l1空了且l2不为空,则temp链表后面项就后应该是l2
return l2;
if(l2==NULL&&l1!=NULL)
return l1;
if(l1==NULL&&l2==NULL)
return NULL;
if(l1->val>l2->val)//比较节点大小
{
temp=l2;//将小节点放入temp中
l2->next=mergeTwoLists(l1,l2->next);//递归,放入节点的链表后移
}
else
{
temp=l1;
l1->next=mergeTwoLists(l1->next,l2);
}
return temp;每递归一次就返回一次
}
来个常规写法,思路是比较大小,然后放入新链表中。代码更好理解
ListNode * mergeTwoLists(ListNode * l1, ListNode * l2) {
// write your code here
ListNode *head=new ListNode(-1);//整一个新节点,来存数据
ListNode *cur=head;
while(l1&&l2)//有一个链表为空就跳出循环
{
if(l1->val>l2->val)
{
cur->next=l2;
l2=l2->next;
}
else
{
cur->next=l1;
l1=l1->next;
}
cur=cur->next;//后移
}
cur->next=l1?l1:l2;//若出现有一个链表为空,将另一个链表放入cur中
//a?b:c 当a为真时,返回b,否则返回c
return head->next;
}
166 · 链表倒数第n个节点(简单)
描述
找到单链表的倒数第n个节点,保证链表中节点的最少数量为n。
样例
样例 1:
输入: list = 3->2->1->5->null, n = 2
输出: 1
样例 2:
输入: list = 1->2->3->null, n = 3
输出: 1
代码实现:
还是使用快慢指针来实现
ListNode * nthToLast(ListNode * head, int n) {
// write your code here
ListNode * fast=head;
ListNode *slow=head;
for(int i=0;i<n;i++)//让快指针往前先走n下
{
fast=fast->next;
}
while(fast!=NULL)//快慢指针一起走
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
167 · 链表求和(简单)
描述
你有两个用链表代表的整数,其中每个节点包含一个数字。数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头。写出一个函数将两个整数相加,用链表形式返回和。
样例
样例 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
代码实现
简单点在于,个位在前,所以只有两个问题需要解决
1.进位的处理。
2.链表可能长度不一致
ListNode * addLists(ListNode * l1, ListNode * l2) {
// write your code here
ListNode *head =new ListNode(-1);//一个新的节点
ListNode *cur=head;//移动的指针
int flag=0;//用来处理进位
while(l1!=0||l2!=0||flag!=0)//只有当两个链表和进位均为零时,才会结束循环
{
//a?b:c 当a为真时,返回b,否则返回c
int l1val=l1!=NULL?l1->val:0;//取到数字,若链表为空,取0
int l2val=l2!=NULL?l2->val:0;
int sum=(l1val+l2val+flag)%10;//记录和,然后对10取余,保证为一位数字
flag=(l1val+l2val+flag)/10;//对和除以10,保存进位
ListNode *nextNode=new ListNode(sum);//创建新节点
cur->next=nextNode;//放入新的节点中
cur=cur->next;//节点后移
if(l1!=NULL)//待处理两个节点的后移操作,因为两个链表可能长度不同,所以需要分别后移,
//若根据循环一起后期会导致越界
{
l1=l1->next!=NULL?l1->next:NULL;
}
if(l2!=NULL)
{
l2=l2->next!=NULL?l2->next:NULL;
}
}
return head->next;
}
173 · 链表插入排序(简单)
描述
用插入排序对链表排序
样例
样例 1:
输入: 0->null
输出: 0->null
样例 2:
输入: 1->3->2->0->null
输出 :0->1->2->3->null
代码实现
ListNode * insertionSortList(ListNode * head) {
// write your code here
ListNode *dummy=new ListNode(-1);
while(head!=NULL)
{
ListNode *temp=dummy;//指向比较的数
ListNode *next=head->next;//标记下一个需要处理的值
while(temp->next!=NULL &&temp->next->val<head->val)//遇到大的值插入然后后移temp
{
temp=temp->next;
}
head->next=temp->next;//head指向temp中的大值
temp->next=head;//temp指向head后面
head=next;//head归位
}
return dummy->next;
}
174 · 删除链表中倒数第n个节点(简单)
代码实现
跟之前找到链表中的倒数第n个节点类似,都是通过快慢指针来找到节点,多了一步删除操作
ListNode * removeNthFromEnd(ListNode * head, int n) {
// write your code here
ListNode * dummy = new ListNode(-1);
dummy->next = head;
ListNode *fast=dummy;
ListNode *slow=dummy;
if(head->next==NULL) return nullptr;
for(int i=0;i<n;i++)
{
fast=fast->next;
}
while(fast->next!=NULL)
{
fast=fast->next;
slow=slow->next;
}
slow->next=slow->next->next;//直接跳过倒数第n个节点
return dummy->next;
}
217 · 无序链表的重复项删除(简单)
描述
设计一种方法,从无序链表中删除重复项。
样例
样例 1:
输入:1->2->1->3->3->5->6->3->null
输出:1->2->3->5->6->null
样例 2:
输入:2->2->2->2->2->null
输出:2->null
代码实现
ListNode * removeDuplicates(ListNode * head) {
// write your code here
map<int, bool>mp;//定义一个map容器来存放数据,对于map容器不了解的,后面有其他人的博客链接
if (head == NULL)
{
return head;
}
mp[head->val] = true;//用链表的数值做key值,如果存在value为true
ListNode* tail = head;//用来保存不重复的值
ListNode* now = head->next;
while (now != NULL)
{
//用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,
//如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器
if (mp.find(now->val)==mp.end())//当出现未出现的值,满足if条件
{
mp[now->val] = true;//赋值
tail->next = now;
tail = tail->next;
}
now = now->next;//后移
}
tail->next = NULL;//尾指针赋空值
return head;
}
map容器介绍:C++ map用法总结(整理)
视频教程链接:map容器构造和赋值
219 · 在排序链表中插入一个节点(简单)
描述
在链表中插入一个节点。
样例
样例 1:
输入:head = 1->4->6->8->null, val = 5
输出:1->4->5->6->8->null
样例 2:
输入:head = 1->null, val = 2
输出:1->2->null
代码实现
ListNode * insertNode(ListNode * head, int val) {
// write your code here
ListNode *dummy=new ListNode(-1);//创建一个新的头节点
dummy->next=head;
ListNode *fast=dummy;
if(head==NULL)//当目标链表为空时,返回给定值的链表
{
ListNode *temp=new ListNode(val);
return temp;
}
while(fast->next!=NULL)
{
if(fast->next->val<val)//当链表节点值小于给定值时,链表指针后移
{
fast=fast->next;
}
else
{
ListNode *temp=new ListNode(val);//创建新节点
ListNode *cur=fast->next;//记录当前节点的指针
fast->next=temp;//指向新节点
temp->next=cur;//指向保存的节点
return dummy->next;
}
}
//当链表走到末尾任然未插入节点时,在末尾插入
ListNode *temp=new ListNode(val);
ListNode *cur=fast->next;
fast->next=temp;
temp->next=cur;
return dummy->next;
}
294 · 简化链表(简单)
描述
给出一个字符链表,对其进行简化。
简化的过程为,保留链表的头尾节点,用数字代替掉中间的部分。
数字也要用字符链表表示。
样例
输入的字符链表用一个整型链表表示,链表的每个节点的值都是其对应的ASCII码。
原链表是 'h'->'e'->'l'->'l'->'o'->null。
简化后变为 'h'->'3'->'o'->null。//将ell这个三个字符用数字三代替
第二组样例中:
原链表是 'a'->'b'->...->'z'->null。
简化后变为 'a'->'2'->'4'->'z'->null。//将b-y的字母用数字24代替
输入1:
104->101->108->108->111->null
输出1:
104->51->111->null
输入2:
97->98->...->122->null
输出2:
97->50->52->122->null
代码实现
ListNode * simplify(ListNode * head) {
//write your code here
ListNode *fast=head;
ListNode *insert=head;
ListNode *slow=head;
int count=-1;//计数变量
while(fast->next)//移动链表
{
fast=fast->next;
count++;
}
string s=to_string(count);//数字转字符
for(int i=0;i<s.size();i++)
{
insert=new ListNode(s[i]);//插入字符
slow->next=insert;//头节点指向新的字符
slow=insert;//节点后移一位
}
slow->next=fast;//指向尾部节点
return head;
372 · 在O(1)时间复杂度删除链表节点(简单)
描述
给定一个单链表中的一个等待被删除的节点(非表头或表尾)。请在在 O(1) 时间复杂度删除该链表节点。
样例
样例 1:
输入:
1->2->3->4->null
3
输出:
1->2->4->null
样例 2:
输入:
1->3->5->null
3
输出:
1->5->null
代码实现
通常情况下的删除节点是要知道被删除节点的前一个节点的,如果按照这种理解,那么这道题是无解的。
只能通过改变节点的值的方式来做了。但是,这样的话,如果要删除的节点是链表中的最后一个,那么也是无法删除的。
void deleteNode(ListNode * node) {
// write your code here
if(node) //先比较后跳转,链表本身就是一个递归结构。
{
node->val = node->next->val;//将后一个节点的值,赋给目标节点
node->next = node->next->next; //当前节点指向下下一个节点
}
}
451 · 两两交换链表中的节点(简单)
描述
给一个链表,两两交换其中的节点,然后返回交换后的链表。
样例
样例 1:
输入:1->2->3->4->null
输出:2->1->4->3->null
样例 2:
输入:5->null
输出:5->null
代码实现
ListNode * swapPairs(ListNode * head) {
// write your code here
ListNode *dummy=new ListNode(-1);
ListNode *slow=head;
ListNode *fast=dummy;
while(slow&&slow->next)
{
ListNode *temp=slow->next->next;
fast->next=slow->next;
fast=fast->next;
fast->next=slow;
fast=fast->next;
fast->next=NULL;
slow=temp;
}
if(slow)
{
fast->next=slow;
}
return dummy->next;
}
452 · 删除链表中的元素(简单)
描述
删除链表中等于给定值 val 的所有节点。
样例
样例 1:
输入:head = 1->2->3->3->4->5->3->null, val = 3
输出:1->2->4->5->null
样例 2:
输入:head = 1->1->null, val = 1
输出:null
代码实现
ListNode * removeElements(ListNode * head, int val) {
// write your code here
if(head == NULL)
{
return NULL;
}
ListNode *prev = head;
ListNode *cur = head->next;
while (cur != NULL)
{
if (cur->val != val)
{
prev = cur;
}
else
{
prev->next = cur->next;
delete(cur);
}
cur = prev->next;
}
ListNode *NewHead = head;
if (head->val == val) {
NewHead = head->next;
delete(head);
}
return NewHead;
}
489 · 链表化数组(简单)
描述
将一个数组变成链表
样例
例1:
输入: [1,2,3,4],
输出: 1->2->3->4->null.
例2:
输入: [1,2],
输出: 1->2->null.
代码实现
ListNode * toLinkedList(vector<int> &nums) {
// write your code here
if(nums.size()==0)
{
return NULL;
}
ListNode *dummy=new ListNode(-1);
ListNode *pre=dummy;
for(int i=0;i<nums.size();i++)
{
pre->next=new ListNode(nums[i]);
pre=pre->next;
}
return dummy->next;
}
756 · 两数相乘(简单)
描述
给出两个链表形式表示的数字,写一个函数得到这两个链表相乘乘积。
样例
样例 1:
输入:9->4->6->null,8->4->null
输出:79464
解释:946*84=79464
样例 2:
输入:3->2->1->null,1->2->null
输出:3852
解释:321*12=3852
代码实现
long long multiplyLists(ListNode * l1, ListNode * l2) {
// write your code here
long long s1=0;
long long s2=0;
//链表转int值然后相乘
while(l1!=NULL||l2!=NULL)
{
if(l1!=NULL)
{
s1=s1*10;
s1+=l1->val;
l1=l1->next;
}
if(l2!=NULL)
{
s2=s2*10;
s2+=l2->val;
l2=l2->next;
}
}
cout<<"s1: "<<s1<<" s2:"<<s2<<endl;
long long ans=s1*s2;
return ans;
}
822 · 相反的顺序存储(简单)
描述
给出一个链表,并将链表的值以倒序存储到数组中。
样例
样例1
输入: 1 -> 2 -> 3 -> null
输出: [3,2,1]
样例2
输入: 4 -> 2 -> 1 -> null
输出: [1,2,4]
代码实现
vector<int> reverseStore(ListNode * head) {
// write your code here
vector<int>ans;
while(head)
{
ans.push_back(head->val);
head=head->next;
}
reverse(ans.begin(),ans.end());
return ans;
}
1609 · 链表的中间结点(简单)
描述
给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
样例
样例 1:
输入:1->2->3->4->5->null
输出:3->4->5->null
样例 2:
输入:1->2->3->4->5->6->null
输出:4->5->6->null
代码实现
ListNode * middleNode(ListNode * head)
{
// write your code here.
ListNode *fast=head;
ListNode *slow=head;
while(fast != NULL && fast->next != NULL)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}