使用递归进行链表合并

leetcode上有合并链表的题,大概是说将k个升序链表合成1个升序链表。(附上原题)

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

方法有很多种,但是如果加上限定:原地合并(不创建新的链表),就有点说法了,先上一个这个题的我觉得贼6的解:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
     if(l1==NULL)
         return l2;
     if(l2==NULL)
         return l1;
     if(l1->val < l2->val){
         l1->next = mergeTwoLists(l1->next,l2);
         return l1;
     }else{
         l2->next = mergeTwoLists(l1,l2->next);
         return l2;
     }
 }

这是一个很标准的递归求解方法;后来我在论坛里看到一个老哥发了一个贴:

看完完之后感觉很熟悉,但是合并之后的增减性变了。那么已开始是无法确定链表的头结点的(不知道两个子链表的结尾谁的大)。这时候需要自底向上解决问题,所以我使用尾递归来尝试解决这个问题。总体思想是:merge返回合并之后的尾节点,然后尾节点指向当前L1和L2的较大值,再返回较小值作为新的尾节点。(想象一下把拉链从底向上拉起来的过程)

List* merge(List* l1, List* l2, List *head) {
	if (!(l1 || l2)) {
		head->next = NULL;
		return head;
	}
	if ((l1 != NULL) && (l2 == NULL)) {
			List* pre = merge(l1->next, l2, head);
			l1->next = NULL;
			pre->next = l1;
			if (!flag) {
				head->next = l1;
				FOUND_HEAD;
			}	
		return l1;
	}
	if ((l1 == NULL) && (l2 != NULL)) {
			List* pre = merge(l1, l2->next, head);
			l2->next = NULL;
			pre->next = l2;
			if (!flag) {
				head->next = l2;
				FOUND_HEAD;
			}	
		return l2;
	}
	else if (l1->val > l2->val) {
		List* pre = merge(l1, l2->next, head);
		if (pre == l1) {
			pre->next = l2;
		}
		else {
			pre->next = l1;
			l1->next = l2;
		}
		return l2;
	}
	else {
		if (l2->val == l1->val) {
			List* pre = merge(l1->next, l2->next, head);
			pre->next = l2;
			l2->next = l1;
			return l1;
		}
		List* pre = merge(l1->next, l2, head);
		if (pre == l2) {
			pre->next = l1;
		}
		else {
			pre->next = l2;
			l2->next = l1;
		}
		return l1;
	}
}

递归的程序分支和第一道题是一样的,只是这次递归需要修改把结点指针重新赋值(容易写懵逼)

测试一波:

int main()
{
	int i, j;
	List* l1, *l2;
	l1 = (List*)malloc(sizeof(List));
	l1->val = 0;
	l1->next = NULL;
	l2 = (List*)malloc(sizeof(List));
	l2->val = 2;
	l2->next = NULL;

	List* pre;
	pre = l1;
	for (i = 1; i < 5; i++) {
		List* current = (List*)malloc(sizeof(List));
		current->next = NULL;
		current->val = i*3;
		pre->next = current;
		pre = current;
	}
	pre = l2;
	for (i = 3; i < 10; i++) {
		List* current = (List*)malloc(sizeof(List));
		current->next = NULL;
		current->val = i;
		pre->next = current;
		pre = current;
	}

	List* current = l1;
	while (current != NULL) {
		printf("%d->", current->val);
		current = current->next;
	}
	printf("NULL\n");
	current = l2;
	while (current != NULL) {
		printf("%d->", current->val);
		current = current->next;
	}

	printf("NULL\n");
	List* head = (List*)malloc(sizeof(List));
	head->next = NULL;
	current = merge(l1,l2,head);
	current->next = NULL;


	current = head->next;
	while (current != NULL) {
		printf("%d->",current->val);
		current = current->next;
	}
	printf("NULL\n");

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值