算法通关村第一关——链表经典问题之双指针专题笔记

所谓的双指针也就是两个变量,在一些链表问题中使用双指针解法可以有效率地解决问题。

1.寻找链表中间结点

比如力扣876给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

思路:这道题就可以使用快慢双指针的思想进行解决,利用两个指针来进行数据索引,一个快的,一个慢的,俗称“龟兔赛跑”。设置两个指针均指向链表头部,慢指针走一步,快指针则走两步。这样当快指针到达链表末尾时,慢指针就正好指向了链表的中间节点。

var middleNode = function(head) {
	let fastPointer = head, slowPointer = head;

	while (fastPointer && fastPointer.next) {
		slowPointer = slowPointer.next;
		fastPointer = fastPointer.next.next;
	}
	return slowPointer;
}

思考:

1).链表数据为偶数时,中间结点有两个,为什么返回靠后的中间结点?

如果链表长度为奇数,那么只有一个中间节点,而慢指针正好指向这个中间节点,所以返回的是唯一的中间节。

但如果链表长度为偶数,有两个中间节点。此时,慢指针指向其中的一个中间节点,而快指针在链表末尾的下一个节点,因此,慢指针指向的是靠后的那个中间节点。

为什么要选择返回靠后的中间节点呢?这其实是一个约定俗成的做法,可以看做是一种设计上的决策。在某些应用中,返回靠后的中间节点可能更符合预期的结果,而在另一些情况下可能会选择返回靠前的中间节点。重要的是,在实现链表操作时,始终遵循相同的规则,以确保一致性。

2).比如1,2,3,4,5使用标准的快慢指针就是后面的4,而在很多数组问题中会是前面的3,为什么会这样?

还有就是数组和链表的的索引起始位置不同,数组为0,链表为1.因此在数组双指针问题,要比链表往左移动一位。

2.寻找倒数第K个元素

找出单向链表中倒数第 k 个节点。

思路:设置两个指针均指向链表头部,先让快指针走k步,此时快指针指向第 k + 1个结点,再让快慢指针同时走,当快指针遍历到链表尾结点时,慢指针此时所指的就是倒数第k个结点。

var getKthFromEnd = function(head, k) {
	let slowPointer = fastPointer = head;

	while (k > 0) {
		fastPointer = fastPointer.next;
		k--;
	}

	while (fastPointer) {
		fastPointer = fastPointer.next;
		slowPointer = slowPointer.next;
	}
	return slowPointer;
}

3.旋转链表

力扣61题,给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

旋转链表

思路:

先用双指针策略找到倒数K的位置,将链表分成两个链表,之后再将两个链表拼接起来即可。

因为K有可能大于链表长度,所以首先遍历一遍链表获取长度lengthOfListNode,若k = k % lengthOfListNode === 0,即刚好旋转一圈,则不用旋转,直接返回头结点。否则先让先让快指针走k步,再让快慢指针同时走,当快指针遍历到链表尾结点时,慢指针此时所指的要断开的结点。让快指针指向的结点链接到原链表头部,慢指针指向的结点断开和下一结点的联系。最后返回结束时慢指针指向的结点的下一结点。

var rotateRight = function(head, k) {
	let slowPointer = fastPointer = tempPointer = head;
	let lengthOfListNode = 0;
	let responseListNode = new ListNode();

	while (head === null | k === 0) return head;

	// 先得出链表长度
	while (head) {
		head = head.next;
		lengthOfListNode++;
	}
	// 这里刚好旋转一圈
	if (k % lengthOfListNode === 0) return tempPointer;

	// k取模是为了防止k大于链表长度的情况
	while (k % lengthOfListNode > 0) {
		fastPointer = fastPointer.next;
		k--;
	}

	while (fastPointer.next) {
		fastPointer = fastPointer.next;
		slowPointer = slowPointer.next;
	}

	responseListNode = slowPointer.next;
	slowPointer.next = null;
	fastPointer.next = tempPointer;

	return responseListNode;

};

4.总结

快慢指针真的是一种简单又很有效率的方法,还可以将其应用到很多链表题目当中。以后刷算法题或者面试时,遇到链表的题目可以优先考虑一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值