链表题 分享

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;

}
}

141. 环形链表

难度简单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;
     }
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值