CM11 链表分割 牛客网
现有一链表的头指针ListNode*pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
思路:
举个例子, 假设x=15,题目给了一个head传入参数,自己定义一个cur作当前的参数放在head位置。(如下图)
新列表里结点小于x的这部分 开头用bs表示(beginstart),结尾用be表示(beginend)。初始的时候be=null,bs=null,所以be和bs初始放在一起画图表示。(如下图)
新列表里结点大于x的这部分 开头用as表示(afterstart),结尾用ae表示(afterend)。(如下图)
public class MySingleLIst {
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
ListNode partition(ListNode head, int x) {
if(head==null)return null;//不要忘记如果列表为空的情况
ListNode bs = null;
ListNode be = null;
ListNode as = null;
ListNode ae = null;
ListNode cur = head;
while (cur != null) {
if (cur.val < x) { //val<x的结点
if (bs == null) { //第一个放在<x部分的结点
bs = cur;
be = cur;
} else { //bs不为空的情况
be.next = cur;
be = be.next;
}
} else { //val大于x的结点
if (as == null) { //第一个放在>x部分的结点
as = cur;
ae = cur;
} else { //as不为空
ae.next = cur;
ae = ae.next;
}
}
cur = cur.next;
}
if (bs == null) { //特殊情况:<x的部分为空
return as;
}
be.next = as; // 连接新列表<x 和 >x的两部分
if(as!=null){ //特殊情况:>x的部分不为空
ae.next=null;
}
return bs; //如果>x的地方为空就返回<x的头
}
}
160. 相交链表 力扣
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
- intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
- listA - 第一个链表
- listB - 第二个链表
- skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
- skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数
评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
空间复杂度O(1)
时间复杂度O(m+n)
思路:
当两个列表不一样:1.算两个列表长度
2.让长的列表先走差值步
3.然后一起走,直到相遇
给一个pl 指向最长的链表 和ps 指向最短的
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA==null||headB==null)return null;
ListNode pl = headA;//永远指向长的链表
ListNode ps = headB;//永远指向短的链表
//求两个链表长度
int leA =0;
int leB =0;
while(pl!=null){
leA++;
pl=pl.next;
}
while(ps!=null){
leB++;
ps=ps.next;
}
pl=headA;
ps=headB;
int le=leA-leB; //计算差值
if(leA-leB<0){
pl=headB;
ps=headA;
le=leB-leA; //更新差值
}
// 走到这里,pl一定指最长的列表,ps指最短的。le为正数。
while(le!=0){ //pl走差值步
le--;
pl=pl.next;
}
//下面pl和ps一起走,直到相遇
while(pl!=ps){
pl=pl.next;
ps=ps.next;
}
return pl;
}
}
难度简单1691收藏分享切换为英文接收动态反馈
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
思路:
快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从起始位置开始走。如果链表带环则一定会在环中相遇,否则快指针先走到链表的末尾。
【扩展问题】
- 快指针一次走3步,走4步,....走n步可以吗?
不可以。如果是下图这样的链表快指针一次走3步肯定是不行的。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null)return false;
ListNode fast =head;
ListNode slow = head;
while(fast!=null && fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
return true;
}
}
return false;
}
}
142. 环形链表 II (力扣)
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/linked-list-cycle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
H为链表的起始点,E为环入口点,M与判环时候相遇点
设: 环的长度为R,H到E的距离为L E到M的距离为X
则: M到E的距离为R- X
在判环时,快慢指针相遇时所走的路径长度:
fast:L +X + nR
slow:L+X
1.当慢指针进入环时,快指针可能已经在环中绕了n圈了,n至少为1
因为:快指针先进环走到M的位置,最后又在M的位置与慢指针相遇
2.慢指针进环之后,快指针肯定会在慢指针走-圈之内追上慢指针
因为:慢指针进环后,快慢指针之间的距离最多就是环的长度,而两个指针
在移动时,每次它们至今的距离都缩减-步,因此在慢指针移动- -圈之前快
指针肯定是可以追上慢指针的
而快指针速度是满指针的两倍,因此有如下关系是:
2*(L+X)=L+X+nR
L+X=nR
L= nR- X (n为1.,2.3..... n的大小取决于环的大小,环越小越大)
极端情况下,假设n= 1,此时: L=R-X
即:一个指针从链表起始位置运行,-个指针从相遇点位置绕环,每次都走一
步,两个指针最终会在入口点的位置相遇
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null)return null;
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
break;
}
}
//两种情况。1.不满足循环条件【其中一个为null说明没有环】 2.遇到了break有环且相遇了
if(fast ==null|| fast.next == null){
return null;
}
slow = head;
while(slow!=fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}