《算法通关村第一关——链表经典问题之合并有序链表》

1.合并两个有序链表

解决方法有两种:

新建一个链表,然后分别遍历两个链表,每次都选最小的结点接到新链表上,最后排完。另外一个就是将一个链表结点拆下来,逐个合并到另外一个对应位置上去。 

这里采用第一种:

(1)创建一个空表list3

(2)依次从list1或list2中选取元素值较小的结点插入到list3的最后,直到其中一个表变空为止

(3)继续将list1或list2其中一个表的剩余结点插入到list3的最后

代码如下:

struct ListNode* mergeTowLists(struct ListNode* list1, struct ListNode* list2) {
	struct ListNode *newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode *res = newHead;

	while (list1 && list2) {
		if (list1->val < list2->val) {
			newHead->next = list1;
			list1 = list1->next;
		}
		else if(list1->val>list2->val){
			newHead->next = list2;
			list2 = list2->next;
		}
		else {
			newHead->next = list2;
			list2 = list2->next;
			newHead = newHead->next;
			newHead->next = list1;
			list1 = list1->next;
		}
		newHead=newHead->next;
	}
	while (list1) {
		newHead->next = list1;
		list1 = list1->next;
		newHead=newHead->next;
	}
	while (list2) {
		newHead->next = list2;
		list2 = list2->next;
		newHead=newHead->next;
	}
	return res->next;
}

完整代码:

#include<stdlib.h>
#include<stdio.h>

struct ListNode {
	int val;
	struct ListNode *next;

};
struct ListNode *initList(const int array[],int size) {
	struct ListNode *newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
	newHead->next = NULL;
	struct ListNode *res = newHead;
	
	for (int i = 0; i < size; i++) {
		struct ListNode* q = (struct ListNode*)malloc(sizeof(struct ListNode));
		q->val = array[i];
		q->next = newHead->next;
		newHead->next = q;
		newHead = newHead->next;
	}
	return res->next;
}
void printList(struct ListNode *p) {
	struct ListNode *temp = p;
	while (temp) {
		//struct ListNode* f = temp;
		printf("%d", temp->val);
		temp = temp->next;
		//free(f);
	}
	printf("\n");
}
struct ListNode* mergeTowLists(struct ListNode* list1, struct ListNode* list2) {
	struct ListNode *newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode *res = newHead;

	while (list1 && list2) {
		if (list1->val < list2->val) {
			newHead->next = list1;
			list1 = list1->next;
		}
		else if(list1->val>list2->val){
			newHead->next = list2;
			list2 = list2->next;
		}
		else {
			newHead->next = list2;
			list2 = list2->next;
			newHead = newHead->next;
			newHead->next = list1;
			list1 = list1->next;
		}
		newHead=newHead->next;
	}
	while (list1) {
		newHead->next = list1;
		list1 = list1->next;
		newHead=newHead->next;
	}
	while (list2) {
		newHead->next = list2;
		list2 = list2->next;
		newHead=newHead->next;
	}
	return res->next;
}


int main() {
	struct ListNode* list1 = NULL;
	struct ListNode* list2 = NULL;
	printf("creat list: \t\n");

	int a[] = { 1,2,3 };
	int b[] = { 1,3,4 };
	list1 = initList(a, 3);
	list2 = initList(b, 3);

	struct ListNode *list3 = mergeTowLists(list1, list2);
	printList(list3);
	return 0;
}

 优化代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
	struct ListNode* prehead = (struct ListNode*)malloc(sizeof(struct ListNode));
	struct ListNode* prev = prehead;

	while (list1 && list2)
	{
		if (list1->val <= list2->val)
		{
			prev->next = list1;
			list1 = list1->next;
		}
		else
		{
			prev->next = list2;
			list2 = list2->next;
		}
		prev = prev->next;
	}

	prev->next = list1 == NULL ? list2 : list1;
	return prehead->next;
}

 2.合并K个链表

先将前两个合并,之后再将后面的逐步合并起来。

代码如下:

struct ListNode* mergeKLists(struct ListNode* lists[],int size){
struct ListNode* res=NULL;

for(int i=0;i<size;i++){
res=mergeTowLists(res,lists[i]);
}
return res;
}

 3.LeetCode1669

题目:给你两个链表list1和list2,它们包含的元素分别为n个和m个。请你将list1中下标从a到b的结点删除,并将list2接在被删除结点的位置。

题目意思:将list1中的[a,b]区间删掉,然后将list2接进去,如下图所示:

 代码如下:

struct ListNode *mergeInBetween(struct ListNode *list1, int a, int b, struct ListNode *list2)
{
    struct ListNode *pre1 = list1;
    struct ListNode *post1 = list1;
    struct ListNode *post2 = list2;
    int i = 0, j = 0;

    // 寻找list1中的节点pre1和post1
    while (pre1 != NULL && post1 != NULL && j < b)
    {
        if (i != a - 1)
        {
            pre1 = pre1->next;
            i++;
        }
        if (j != b)
        {
            post1 = post1->next;
            j++;
        }
    }

    post1 = post1->next;

    // 寻找list2的尾节点
    while (post2->next != NULL)
    {
        post2 = post2->next;
    }

    // 链1尾接链2头,链2尾接链1后半部分的头
    pre1->next = list2;
    post2->next = post1;

    return list1;
}

注意:题目中开闭区间的情况。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值