链表相关辅助函数
链表结构
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
数组创建链表
ListNode* creat(int num[], int n)
{
if (n == 0)return NULL;
ListNode* head = new ListNode( num[0]);
ListNode* ret = head;
for (int i = 1;i < n;i++)
{
head->next = new ListNode(num[i]);
head = head->next;
}
return ret;
}
向量创建链表
ListNode* creat(vector<int> num)
{
if (num.size() == 0)return NULL;
ListNode* head = new ListNode(num[0]);
ListNode* ret = head;
for (int i = 1;i < num.size();i++)
{
head->next = new ListNode(num[i]);
head = head->next;
}
return ret;
}
链表末尾插入元素
ListNode* insert(ListNode* head,int num)
{
if (head == NULL)
return new ListNode(num);
ListNode* tmp = head;
while (tmp->next != NULL)
{
tmp = tmp->next;
}
tmp->next = new ListNode(num);
return head;
}
删除和打印
void deletelink(ListNode* head)
{
ListNode* tmp;
while (head!= NULL)
{
tmp = head->next;
delete head;
head = tmp;
}
}
void printlist(ListNode* head)
{
while (head != NULL)
{
cout << head->val << "->";
head = head->next;
}
cout << "NULL"<< endl;
}
链表节点间穿针引线
206. 反转链表
题目描述

方法1 迭代
ListNode* reverseList1(ListNode* head) {
if (head == NULL)return head;
ListNode* pre = head;
ListNode* tmp = head->next; //要反转的链表
ListNode* next; //缓存下一个
while (tmp != NULL)
{
next = tmp->next;//缓存
tmp->next = pre;//反转
pre = tmp;//移动
tmp = next;//移动
}
head->next = NULL;//头节点
return pre;
}
方法2 递归
1->2->3->4
递归返回 4->3->NULL
对于节点2
2->next=3
2->next->next=2
变成
4->3->2
2->next=NULL
变成
4->3->2->NULL
返回头节点4 完成反转
ListNode* preverse(ListNode* node)
{
if (node->next == NULL)
{
return node;
}
else
{
ListNode* tmp=preverse(node->next);//返回已经反转过的链表的头节点
node->next->next = node;//当前节点
node->next = NULL;
return tmp;
}
}
ListNode* reverseList(ListNode* head) {
if (head->next == NULL||head==NULL)
{
return head;
}
else
{
ListNode* tmp = preverse(head->next);
head->next->next = head;
head->next = NULL;
return tmp;
}
}
92. 反转链表 II
题目描述

方法1 缓存相关节点
ListNode* reverseBetween(ListNode* head, int m, int n) {
if (head == NULL || head->next == NULL||m==n)return head;
ListNode* tmp;
ListNode* pre=head;
ListNode* next;
ListNode* res1 = new ListNode(-1);// 重点 打造虚拟头结点
ListNode* res2 = res1;//缓存头结点位置
res1->next = head;
int count = 0;
while (count < m-1) {
res1 = res1->next;//开始反转的前一个元素位置缓存
count++;
}
pre = res1->next;
tmp = pre->next;
while (count < n-1)//找到终止位置
{
next = tmp->next;//依次反转节点
tmp->next = pre;
pre = tmp;
tmp = next;
count++;
}
res1->next->next = tmp;//反转的起始元素连接末尾
res1->next = pre;//链表的起始连接反转末尾
ListNode* ret = res2->next;
res2->next = NULL;
delete res2;//释放内存
return ret;
}
83. 删除排序链表中的重复元素
题目描述

方法1 保留第一个重复元素
ListNode* deleteDuplicates1(ListNode* head) {
if (head == NULL || head->next == NULL)
{
return head;
}
ListNode* pre = head;//看前一个元素
ListNode* tmp = head->next;
//ListNode* next = NULL;
while (tmp!=NULL)
{
while (tmp!=NULL&&tmp->val == pre->val)//出现重复
{
pre->next = tmp->next;//删除第后面出现的元素
delete tmp;
tmp = pre->next;
}
pre = tmp;//向后移动
if (tmp != NULL)
{
tmp = tmp->next;
}
}
return head;
}
方法2 保留第一个重复元素优化
ListNode* deleteDuplicates2(ListNode* head) {
ListNode* tmp = head;//看后一个元素
while (tmp != NULL && tmp->next != NULL)
{
if (tmp->val == tmp->next->val)
{
tmp->next = tmp->next->next;
}
tmp = tmp->next;
}
return head;
}
86. 分隔链表
题目描述

方法1 根据大小划分成两个子链表再合并
ListNode* partition(ListNode* head, int x) {
ListNode* lesshead=new ListNode(-1);
ListNode* largehead= new ListNode(-1);
ListNode* lres = lesshead;//值小的数
ListNode* larres = largehead;//值大的数
while (head != NULL)
{
if (head->val < x)
{
lesshead->next = head;
head = head->next;
lesshead = lesshead->next;
}
else
{
largehead->next = head;
head = head->next;
largehead = largehead->next;
}
}
largehead->next = NULL;
lesshead->next = larres->next;
head = lres->next;
delete lres;
delete larres;
return head;
}
328. 奇偶链表
题目描述

方法1 分成两个子链表再合并
ListNode* oddEvenList(ListNode* head) {
ListNode* lesshead = new ListNode(-1);
ListNode* largehead = new ListNode(-1);
ListNode* lres = lesshead;
ListNode* larres = largehead;
while (head != NULL)
{
lesshead->next = head;//奇数
head = head->next;
lesshead = lesshead->next;
if(head!=NULL)
{
largehead->next = head;//偶数
head = head->next;
largehead = largehead->next;
}
}
largehead->next = NULL;
lesshead->next = larres->next;
head = lres->next;
delete lres;
delete larres;
return head;
}
2. 两数相加
题目描述

方法1 转化成整数在转化成链表(数字太大会溢出)
ListNode* addTwoNumbers1(ListNode* l1, ListNode* l2) {
long long a1 = 0;
long long a2 = 0;
long long count = 1;
while (l1 != NULL)
{
a1 = l1->val * count + a1;
l1 = l1->next;
count = count * 10;
}
count = 1;
while (l2 != NULL)
{
a2 = count * l2->val + a2;
l2 = l2->next;
count = count * 10;
}
int a3 = a1 + a2;
vector<long long> ret;
if (a3 == 0)
{
ret.push_back(0);
}
while (a3 != 0)
{
ret.push_back(a3 % 10);
a3 = a3 / 10;
}
ListNode* rett = creat(ret);
return rett;
}
方法2 从头到尾依次按位相加
ListNode* addTwoNumbers2(ListNode* l1, ListNode* l2) {
ListNode* head1 = l1;
ListNode* head2 = l2;
bool addflag = false;
bool l1flag = false;
bool r1flag = false;
int value1 = 0;
int value2 = 0;
ListNode* rettmp = new ListNode(-1);
ListNode* ret = rettmp;
//rettmp = rettmp->next;
while (head1 != NULL || head2 != NULL)
{
// addflag = false;
if (head1 == NULL)//l1加完了
{
l1flag == true;
value1 = 0;
value2 = head2->val;
head2 = head2->next;
}
else if (head2 == NULL)//l2加完了
{
r1flag == true;
value1 = head1->val;
head1 = head1->next;
value2 = 0;
}
else
{
value1=head1->val;
head1 = head1->next;
value2 = head2->val;
head2 = head2->next;
}
int tmp = value1 + value2+int(addflag);//进位
if (tmp >= 10)
{
addflag = true;
tmp = tmp % 10;
}
else
{
addflag = false;
}
rettmp->next = new ListNode(tmp);//注意这里不是rettmp=new node 否则会成为NULL转为listnode
rettmp = rettmp->next;
}
if (addflag == true)//最后是否有进位
{
rettmp = new ListNode(1);
}
ListNode* res = ret->next;
delete ret;
return res;
}
445. 两数相加 II
题目描述

方法1 使用栈逆序再转化成链表
ListNode* addTwoNumbers3(ListNode* l1, ListNode* l2) {
ListNode* p = l1;
ListNode* q = l2;
stack<int> pstack;
stack<int> qstack;
stack<int> kstack;//结果储存位置
ListNode* ret = new ListNode(-1);
ListNode* rettmp = ret;
while (p != NULL)
{
pstack.push(p->val);//入栈
p = p->next;
}
while (q != NULL)
{
qstack.push(q->val);//入栈
q = q->next;
}
int value1 = 0;
int value2 = 0;
int tmp;
bool addflag = false;
while (!pstack.empty() || !qstack.empty())
{
value1 = 0;
value2 = 0;
if (!pstack.empty())
{
value1 = pstack.top();
pstack.pop();
}
if (!qstack.empty())
{
value2 = qstack.top();
qstack.pop();
}
tmp = value1 + value2 + int(addflag);
addflag = tmp >= 10 ? true : false;
tmp = tmp % 10;
kstack.push(tmp);//储存结果
}
if (addflag == true)
{
kstack.push(1);
}
while (!kstack.empty())//转化成链表
{
ret->next = new ListNode(kstack.top());
kstack.pop();
ret = ret->next;
}
ListNode* res = rettmp->next;
delete rettmp;
return res;
}
方法2 使用栈优化
ListNode* addTwoNumbers4(ListNode* l1, ListNode* l2) {
ListNode* p = l1;
ListNode* q = l2;
stack<int> pstack;
stack<int> qstack;
stack<int> kstack;
ListNode* ret = NULL;
// ListNode* rettmp = ret;
while (p != NULL)
{
pstack.push(p->val);
p = p->next;
}
while (q != NULL)
{
qstack.push(q->val);
q = q->next;
}
int value1 = 0;
int value2 = 0;
int tmp;
bool addflag = false;
while (!pstack.empty() || !qstack.empty()||addflag)//addflag 避免对于最后一位进行冗余代码
{
value1 = 0;
value2 = 0;
if (!pstack.empty())
{
value1 = pstack.top();
pstack.pop();
}
if (!qstack.empty())
{
value2 = qstack.top();
qstack.pop();
}
tmp = value1 + value2 + int(addflag);
addflag = tmp/10;
tmp = tmp % 10;
ListNode* res = new ListNode(tmp);
res->next = ret;//链表增加节点 之后把新节点的next指向之前的链表
ret = res;
}
return ret;
}
方法3 链表对齐后使用双指针
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int count = 0, temp;
ListNode* head, * last;
for (head = l1; head; head = head->next)
count++;
for (head = l2; head; head = head->next)
count--;
if (count < 0) //计算两链表长度,将l1指向长链,l2指向短链,将l2的值加到l1中
swap(l1, l2);
last = head = new ListNode(0); //在链首加一个值为0的节点作为初始的last节点,如果最终该节点值仍为0则删除该节点
head->next = l1;
for (int i = abs(count); i != 0; i--) { //将两链数位对齐
if (l1->val != 9)
last = l1;
l1 = l1->next;
}
while (l1) {
temp = l1->val + l2->val;
if (temp > 9) { //如果发生进位,则更新last到l1之间所有数位的值
temp -= 10; //进位后当前数位最大值为8,故将last指针指向当前数位
last->val += 1;
last = last->next;
while (last != l1) {
last->val = 0;
last = last->next;
}
}
else if (temp != 9)
last = l1;
l1->val = temp;
l1 = l1->next;
l2 = l2->next;
}
return head->val == 1 ? head : head->next;
}
设立虚拟头节点
203. 移除链表元素
题目描述

方法1 设立虚拟头节点
ListNode* removeElements1(ListNode* head, int val) {
ListNode* dummyhead = new ListNode(-1);
dummyhead->next = head;
ListNode* cur = dummyhead;
while (cur->next != NULL)
{
if (cur->next->val == val)
{
ListNode* delnode = cur->next;
cur->next = delnode->next;
delete delnode;
}
else//用else
{
cur = cur->next;
}
}
ListNode* ret = dummyhead->next;
delete dummyhead;
return ret;
}
方法2 对头节点单独处理
ListNode* removeElements(ListNode* head, int val) {
while (head != NULL && head->val == val)
{
ListNode* delnode = head;
head = delnode->next;
delete delnode;
}
if (head == NULL)return NULL;
ListNode* cur = head;
while (cur->next != NULL)
{
if (cur->next->val == val)
{
ListNode* delnode = cur->next;
cur->next = delnode->next;
delete delnode;
}
else//用else
{
cur = cur->next;
}
}
return head;
}
82. 删除排序链表中的重复元素 II
题目描述

方法1 使用flag判断当前节点是否是最后一个重复元素
ListNode* deleteDuplicates3(ListNode* head) {
ListNode* dummyhead = new ListNode(-1);
dummyhead->next = head;
ListNode* cur = dummyhead;
ListNode* next = cur->next;
int val;
while (cur->next != NULL)
{
//if(cur->next->val==val)
val = cur->next->val;
next = next->next;
bool delflag = false;
while (next != NULL && next->val == val)//如果有重复 删除第二个节点
{
ListNode* delnode = next;//删除第二个节点
cur->next->next = next->next;//前面指针连接后面指针
next = next->next;//next后移
delete delnode;
delflag = true;
}
if (delflag == true)//删除当前节点
{
ListNode* delnode = cur->next;
cur->next = delnode->next;
delete delnode;
next = cur->next;//next指向下一个
}
else//不需要删除节点
{
cur = cur->next;//直接后移
next = cur->next;//直接后移
}
}
ListNode* res = dummyhead->next;
delete dummyhead;
return res;
}
复杂的穿针引线
24. 两两交换链表中的节点
题目描述

方法1 缓存多个节点
ListNode* swapPairs(ListNode* head) {
ListNode* dummyhead = new ListNode(-1);
dummyhead->next = head;
ListNode* pre = dummyhead;
while (pre->next != NULL && pre->next->next != NULL)
{
ListNode* node1 = pre->next;
ListNode* node2 = node1->next;
node1->next = node2->next;
node2->next = node1;
pre->next = node2;
pre = node1;
}
ListNode* ret = dummyhead->next;
delete dummyhead;
return ret;
}
25. K 个一组翻转链表
题目描述

方法1
ListNode* reverse(ListNode* head)//子函数
{
//ListNode* dummyhead = new ListNode(-1);
//dummyhead->next = head;
ListNode* pre = head;
ListNode* cur = pre->next;
ListNode* next;
while (cur != NULL)
{
next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
head->next = NULL;
return pre;
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummyhead = new ListNode(-1);
dummyhead->next = head;
ListNode* pre = dummyhead;
ListNode* cut = pre;
int count = 0;
while (pre->next != NULL)
{
count = 0;
ListNode* tmpreverst;// = pre;
ListNode* tmphead = pre->next;
cut = pre;
while (cut->next!=NULL&&count < k)
{
cut = cut->next;
count++;
}
if (count != k)//处理结尾不够k个
{
break;
}
tmpreverst = cut->next;//提前缓存
cut->next = NULL;//next设置为NULL
pre->next = reverse(tmphead);//反转链表
tmphead->next = tmpreverst;
pre = tmphead;
}
ListNode* ret = dummyhead->next;
delete dummyhead;
return ret;
}
147. 对链表进行插入排序
题目描述

方法1
ListNode* insertionSortList(ListNode* head) {
ListNode* dummyhead = new ListNode(-1);
dummyhead->next = head;
ListNode* pre = dummyhead->next;
ListNode* cur;// = pre->next;
bool del = false;
while (pre->next != NULL)
{
cur = pre->next;
while (cur!=NULL&&pre->val < cur->val)//找到删除的节点
{
pre = cur;
cur = cur->next;
}
if (cur == NULL)
break;
pre->next = cur->next;//移除之前节点
// pre = dummyhead;
ListNode* tpre = dummyhead;//从头开始遍历找到插入的位置
while (tpre->next->val < cur->val)
{
tpre = tpre->next;
}
ListNode* tmp = tpre->next;
tpre->next = cur;
cur->next = tmp;
//pre=
}
ListNode* ret = dummyhead->next;
delete dummyhead;
return ret;
}
148. 排序链表(还没做)
不仅仅是穿针引线
237. 删除链表中的节点
题目描述

方法1 没有前驱节点 改变链表中的值
void deleteNode(ListNode* node)
{
ListNode* del=node->next;
node->val=del->val;
ListNode* next=del->next;
node->next=next;
delete del;
}
链表与双指针
19. 删除链表的倒数第N个节点
题目描述

方法1 遍历链表统计长度
比较简单
方法2 双指针
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyhead = new ListNode(-1);
dummyhead->next = head;
ListNode* pre = dummyhead;
ListNode* cur=dummyhead;
for (int i = 0; i < n; i++)
{
cur = cur->next;
}
while (cur->next != NULL)//结束条件 后面的指针为空
{
pre = pre->next;
cur = cur->next;
}
ListNode* del = pre->next;
pre->next = del->next;
delete del;
del = dummyhead->next;
delete dummyhead;
return del;
}
61. 旋转链表
题目描述

方法1
ListNode* rotateRight(ListNode* head, int k) {
int len = 0;
ListNode* pre = head;
while (pre != NULL)
{
pre = pre->next;
len++;
}
k = k % len;//找到倒数第k个元素 倒数第k个yuan's元素变成头节点
pre = head;
for (int i = 0; i < k; i++)
{
if (pre->next != NULL)
{
pre = pre->next;
}
else
{
pre = head;
}
}
ListNode* del = head;
if (pre == head)
{
return head;
}
while (pre->next != NULL)
{
pre = pre->next;
del = del->next;
}
ListNode* newhead = del->next;
pre->next = head;
del->next = NULL;
return newhead;
}
143. 重排链表
题目描述

方法1 使用快慢指针找到中间节点并进行归并
void reorderList(ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while (slow->next != NULL&&slow->next->next!=NULL)
{
fast = fast->next;
slow = slow->next->next;
}//找到中间节点
ListNode* newhead = fast->next;
fast->next = NULL;
newhead = reverseNode(newhead);
ListNode* head1 = head;
ListNode* head2 = newhead;
ListNode* ret = new ListNode(-1);
ListNode* re = ret;
while (head1 != 0)
{
ret->next = head1;
head1 = head1->next;
ret = ret->next;
if (head2 != NULL)
{
ret->next = head2;
head2 = head2->next;
ret = ret->next;
}
}
delete re;
//return NULL;
int k = 8;
}
234. 回文链表
题目描述

方法1 快慢指针找到中间的节点
bool isPalindrome(ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while (slow->next != NULL && slow->next->next != NULL)
{
fast = fast->next;
slow = slow->next->next;
}
ListNode* newhead = fast->next;
fast->next = NULL;
newhead = reverseNode(newhead);//逆序其中一个链表
ListNode* head1 = head;
ListNode* head2 = newhead;
while (head1 != NULL)//依次对比
{
if (head1->val != head2->val) { return false; }
head1 = head1->next;
head2 = head2->next;
if (head2 == NULL)
{
break;
}
}
return true;
}
本文深入解析链表数据结构及算法,涵盖链表创建、反转、排序、删除重复元素等核心操作,通过实例代码详细说明各种技巧与优化方法。

被折叠的 条评论
为什么被折叠?



