链表习题(二)

1.查找单链表的倒数第K个节点

  • 设置两个指针(一个记为快指针,一个记为慢指针),都先指向头节点
  • 让快指针先走k-1步
  • 快、慢指针都一步一步往下走,知道快指针为空,慢指针所在位置就是K节点所在位置
struct ListNode* FindKthToTail(struct ListNode* PListHead, unsigned int k) {
	if (PListHead == NULL) { return null; }
	struct ListNode *front = PListHead;
	struct ListNode *back = PListHead;
	//让前面的先走k-1步
	for (int i = 0; i < k-1; i++) {
		front = front->next;
	}
	while (front != NULL) {
		front = front->next;
		back = back->next;
	}
	return back;
}

2.在一个排序的链表中,删除该链表中重复的结点,重复的结点不保留,返回链表头指针

  1. 先设置3个指针,prev指向头节点、p1也指向头节点,p2指向头节点的下一个节点
  2. 比较p1和p2的值是否相等,若不相等,则三个指针都往后走一步;若相等,则p2指针往后走一步,其他两个指针不动,直到p2指针走到下一个不相等的位置。
  3. 删重复节点(p1到p2指针指向的前一个节点都是重复的)
  4. 设置一个节点,它的一个地址的指向为头节点(因为若头节点也是重复节点,早被删除)
struct ListNode* deleteDuplication(struct ListNode* pHead) {
	if (pHead == NULL) { return NULL; }
	struct ListNode *fake = (struct ListNode *)malloc(sizeof(struct ListNode));
	fake->next = pHead;//假结点

	struct ListNode *prev = fake;
	struct ListNode *p1 = pHead;
	struct ListNode *p2 = pHead->next;

	while (p2 != NULL) {
		if (p1->val != p2->val) {
			prev = p1; p1 = p2; p2 = p2->next;
		}
		else {
			while (p2 != NULL && p2->val == p1->val) {
				p2 = p2->next;
			}
			struct ListNode *cur = p1;
			while (cur != p2) {
				struct ListNode *next = cur->next;
				free(cur);
				cur = next;
			}
			prev->next = p2;
			p1 = p2;
			if (p2 != NULL) { p2 = p2->next; }
		}
	}
	pHead = fake->next;
	free(fake);
	return pHead;
}

3.找两个单链表的交点

  1. 先求两个链表相差的长度。
  2. 设置两个指针(快、慢指针问题)
  3. 快指针先走相差的长度-1步,如果快、慢指针不相等,则快、慢指针各往后走一步
  4. 返回快指针
int getLength(struct ListNode *head) {
	int len = 0;
	for (struct ListNode *n = head; n; n = n->next) {
		len++;
	}
	return len;
}
struct ListNode* getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
	int lenA = getLength(headA);
	int lenB = getLength(headB);

	struct ListNode *longer = headA;
	struct ListNode *shorter = headB;
	int diff=lenA - lenB;
	if (lenB > lenA) {
		longer = headB;
		shorter = headA;
		diff = lenB - lenA;
	}
	for (int i = 0; i < diff; i++) {
		longer = longer->next;
	}
	while (longer != shorter) {
		longer = longer->next;
		shorter = shorter->next;
	}
	return longer;
}

4.复杂链表的复制

一个链表的每个结点,有一个指向next指针指向下一个结点,还有一个random指针指向这个链表的随机结点或者NULL,返回复制后的新链表。
定义复杂链表的结构

typedef struct RNode {
    int val;
    struct RNode *next;
    struct RNode *random;
}RNode;

RNode* Copy(RNode* head) {
	//1.只复制结点中的value和next,让新结点跟在老结点后边
	//2.再处理random复制
	//3.把链表拆成两个
	if (head == NULL) { return NULL; }
	RNode *oldNode = head;
	while (oldNode != NULL) {
		RNode *newNode = (RNode*)malloc(sizeof(RNode));
		newNode->val = oldNode->val;

		RNode *oldNext = oldNode->next;
		newNode->next = oldNext;
		oldNode->next = newNode;

		oldNode = oldNext;

		oldNode = head;
		while (oldNode != NULL) {
			RNode *newNode = oldNode->next;
			if (oldNode->random == NULL) {
				newNode->random = NULL;
			}
			else {
				newNode->random = oldNode->random->next;
			}
			oldNode = newNode->next;

		}
		oldNode = head;
		newNode = head->next;
		while (oldNode != NULL) {

			RNode *newNode = oldNode->next;
			oldNode->next = newNode->next;
			if (newNode->next != NULL) {
				newNode->next = newNode->next->next;
			}
			oldNode = oldNode->next;
		}
		return newNode;
	}
}

 

以下是一些C++链表习题及对应代码示例: 1. **反转链表**:将一个单链表反转。 ```cpp /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode* reverseList(ListNode* head) { ListNode *cur = head, *pre = nullptr, *next = nullptr; while(cur) { next = cur->next; cur->next = pre; pre = cur; cur = next; } return pre; } }; ``` 此代码通过迭代的方式,依次改变链表节点的指向,实现链表反转 [^1]。 2. **反转链表(另一种实现)**: ```cpp struct ListNode { int val; struct ListNode *next; }; typedef struct ListNode LN; struct ListNode* reverseList(struct ListNode* head) { if (head==NULL) return head; LN *n1, *n2, *n3; n1 = NULL; n2 = head; n3 = head->next; while(n2) { n2->next = n1; n1 = n2; n2 = n3; if(n3) n3 = n3->next; } return n1; } ``` 同样是反转链表的功能,采用不同的变量命名和逻辑流程 [^2]。 3. **查找两个链表的交点**:找出两个单链表相交的起始节点。 ```cpp struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { struct ListNode *cur1 = headA; struct ListNode *cur2 = headB; int countA = 0, countB = 0; while(cur1) { ++countA; cur1 = cur1->next; } while(cur2) { ++countB; cur2 = cur2->next; } //此时的count就记录了两个链表的长度 cur1 = headA; cur2 = headB; int gap = abs(countA - countB); if(countA < countB) //B链更长,应该B先走差距步,让俩个链表起始位置一样 { while(gap--) { cur2 = cur2->next; } } else { while(gap--) { cur1 = cur1->next; } } //走到这两个链表就是一样长 //假设两个链表相交那么走会在末尾之前找到一个节点,两个val一样 while(cur1) { if(cur1 == cur2) { return cur2; } else { cur1 = cur1->next; cur2 = cur2->next; } } return NULL; } ``` 该代码先计算两个链表的长度,然后让长链表的指针先走长度差的步数,最后同时移动两个指针,找到相交节点 [^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值