链表应用题
1. 递归删除指定值(无头结点)
void Del(ListNode* L,int val){
ListNode* p;//指向被删除节点
if(L==NULL) return;//递归边界
if(L->val==val){//处理首指针
p = L;
L = L->next;
free(p);//删除节点
Del(L,val);//递归调用
}
else Del(L->next,val);//递归调用
}
2. 循环删除指定值(有头结点)
void Del(ListNode* L,int val){
ListNode* p = L->next;//遍历节点
ListNode* pre = L;//辅助删除节点
ListNode* q;//删除节点
while(p!=NULL){//遍历节点存在
if(p->val==val){//找到指定值,更改指针结构
q = p;
p = p->next;
pre->next = p;
free(q);
}
else{
pre = p;
p = p->next;
}
}
}
3. 反向输出每个值(有头结点)
//主函数从头结点下一个节点调用函数
void rprint(ListNode* L){
if(L->next) rprint(L->next);//入栈
print(L->val);
}
4. 删除最小值(有头结点)
void del_min(ListNode* L){
ListNode* pre = L; ListNode* p = pre->next;
ListNode* minpre = pre; ListNode* minp = p;
while(p){
if(p->val<minp->val){
minp = p;
minpre = pre;
}
pre = p;
p = p->next;
}
minpre->next = minp->next;
free(minp);
}
5. 就地逆置(有头结点)
ListNode* reverseList(ListNode* head) {
ListNode*pre= head;
head = head->next;
ListNode*node;//插入节点
while(head){
node = head;
head = head->next;
node->next = pre->next;
pre->next = node;
}
return pre;
6. 递增有序(有头结点)
void sort(ListNode* head){
ListNode* p = head->next;//遍历节点
head->next = NULL;//断链
ListNode* node;//插入节点
while(p){
node = p;
p = p->next;
insert(head,node);//插入重构链表
}
}
void insert(ListNode* pre,ListNode* node){//将node插入到头结点为pre的链表中
while(pre->next&&pre->next->val<node->val)
pre = pre->next;//找到插入位置的前驱
node->next = pre->next;
pre->next = node;
}
7. 删除指定范围值(与题2基本一致)
8. 求两链表公共节点(相交链表)
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (headA == NULL || headB == NULL)
return NULL;
ListNode *pA = headA, *pB = headB;
while (pA != pB) {
pA = pA == NULL ? headB : pA->next;
pB = pB == NULL ? headA : pB->next;
}
return pA;
}
9. 递增输出并释放(循环调用题4函数)
10. 按奇偶拆分
ListNode * split(ListNode *A){
int i =0;//判断序号
ListNode * B = new ListNode();
ListNode * ra = A, rb = B;//链表遍历指针
ListNode *p = A->next;//拆分A的遍历指针
while(p){//每次处理一个元素
i++;
if(i%2==0) rb->next=p,rb=p;//更改下条件可以用来处理奇数偶数
else ra->next=p,ra=p;
p = p->next;
}
ra->next = NULL;
rb->next = NULL;
return B;
}
11. 按奇偶拆分(奇尾插、偶头插)
12. 递增有序去重
void Del_same(ListNode* head){
ListNode* p = head->next;//遍历指针
if(p==NULL) return;
while(p->next){//下一节点存在
ListNode* q = p->next;
if(p->val==q->val){//删除节点
p->next = q->next;
free(q);
}
else p = p->next;
}
}
13. 合并两升序链表并反转
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2){
ListNode* p1 = l1->next;
ListNode* p2 = l2->next;
l1->next = NULL;//l1作为返回值,原地修改
ListNode* r;//记录辅助插入
while(p1&&p2){
if(p1->val<=p2->val){//头插较小值
r = p1;
p1 = p1->next;
r->next = l1->next;
l1->next = r;
}
else{//一样操作
r = p2;
p2 = p2->next;
r->next = l1->next;
l1->next = r;
}
}
if(p2) p1 = p2;//统一操作
//处理剩下的链表
while(p1){
r = p1;
p1 = p1->next;
r->next = l1->next;
l1->next = r;
}
return l1;
}
14. 产生公共链表
//每次移动较小元素直到找到公共部分
ListNode* common(ListNode* l1, ListNode* l2){
ListNode*p = l1->next;
ListNode*q = l2->next;//遍历节点
ListNode* l3 = new ListNode();
ListNode* r = l3;//尾插遍历节点
while(p&&q){
if(p->val<q->val) p = p->next;
else if(p->data>q->data) q = q->next;
else{
ListNode* s = new ListNode(p->val);//复制节点信息
r->next = s;
r = r->next;//尾插复制节点
p = p->next;
q = q->next;
}
}
}
15. 求链表交集(与题14基本一致)
16. 判断连续子序列
bool Pattern(ListNode* l1, ListNode* l2){
//也可以通过遍历l1,回溯l2的形式来实现
if(l1==NULL) return false;//边界条件一
if(l2==NULL) return true//边界条件二
if(l1->val==l2->val) return Pattern(l1->next,l2->next)|Pattern(l1->next,l2);
else Pattern(l1->next,l2);
}
17. 判断循环双链表对称(有头结点)
bool Symmetry(ListNode* L){
ListNode* p = L->next;
ListNode* q = L->prior;
while(p!=q&&q->next!=p){
if(p->val==q->val){
p = p->next;
q = q->prior;
}
else return false;
}
return true;
18. 串联两循环单链表
ListNode* Symmetry(ListNode* l1,ListNode*l2){
ListNode* p = l1;
ListNode* q = l2;//遍历找尾结点
while(p->next!=l1) p = p->next;
while(q->next!=l2) q = q->next;
//更改结构
p->next = l2;
q->next = l1;
return l1;
19. 重复删除循环单链表最小值
//与不循环的只是判空和遍历结束条件不同
ListNode* Del(ListNode* L){
ListNode* p,*pre,*minp,*minpre;
while(L->next!=L){//重复查找删除至空
p = L->next; pre = L;
minp = p; minpre = pre;
while(p!=L){//遍历全链表
if(p->val<minp->val){
minp = p;
minpre =pre;
}
pre = p;
p = p->next;
}
//输出最小值minp->val
minpre->next = minp->next;
free(minp);
}
}
20. 双链表按频递减
ListNode* Locate(ListNode* L,int val){
ListNode* p = L->next;//遍历节点
while(p&&p->val!=val)
p = p->next;//找对应节点
if(!p) exit(0);//不存在该节点,查找失败
p->freq++;//频率加
if(p->next) p->next->prior = p->prior;//摘除该节点
p->prior->next = p->next;
ListNode* q = p->prior;//往前遍历节点
while(q!=L&&q->freq<=p->freq)
q = q->prior;
//将p插入q的后面
p->next = q->next;
q->next = p;
p->prior = q;
p->next->prior = p;
}
21. 倒数第k个节点
快慢指针
ListNode* getKthFromEnd(ListNode* head, int k) {
ListNode* p1 =head;
ListNode* p2 =head;
for(int i=0;i<k;i++) p2=p2->next;
while(p2){
p1=p1->next;
p2=p2->next;
}
return p1;
}
22. 字符链表的公共节点(相交链表)与题8等同
23. 删除绝对值重复节点
数组做哈希表,其他操作与删除指定元素一样
void Del(ListNode* L){
ListNode* p = L->next;//遍历节点
ListNode* pre = L;//辅助删除节点
ListNode* q;//删除节点
int* hash = (int*)malloc(sizeof(int)*(n+1));//哈希表
memset(hash,0,sizeof(int)*(n+1));//初始化为0
while(p){//遍历节点存在
if(hash[abs(p->val)]==0){//没出现过该元素绝对值,后移
pre = p;
p = p->next;
}
else{//否则删除该值
q = p;
p = p->next;
pre->next = p;
free(q);
}
hash[abs(p->val)]++;
}
}
24. 找环的入口
先快慢指针找相遇位置,此时快指针距离是慢指针两倍,它们的差同样也是环的n倍
可知慢指针已经走了环的n倍距离,此时通过重置快指针,让慢指针再走环外距离,使其到达环的入口处
//快慢指针
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode * fast = head;
ListNode * slow = head;
while(true){
if(!fast||!fast->next) return NULL;
slow = slow->next;
fast = fast->next->next;
if(slow==fast) break;
}
fast = head;
while(fast!=slow)
fast=fast->next,slow=slow->next;//slow在循环中转圈
return fast;
}
};
25. 重排链表
排列成(1,n,2,n-1,3,n-2...)的形式
快慢指针找中点,逆置中点后链表,再依次插入
ListNode* change(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast->next) {
slow = slow->next;
fast = fast->next;
if(fast->next) fast = fast->next;
}
fast = slow->next;//fast指向后半段链表
slow->next = NULL;//断链
while(fast){//逆置后半段链表
ListNode* r = fast;//辅助插入节点
fast = fast->next;
r->next = slow->next;//slow作为头进行头插
slow->next = r;
}
ListNode* s = head->next;//插入点,插入其后
fast = slow->next;//重置fast为后半第一个节点
slow->next = NULL;//断链
while(fast){
ListNode* r = fast;//辅助插入节点
fast = fast->next;
r->next = s->next;
s->next = r;
s = r->next;//跳一个位置
}
}