LinkedList 合并、环的长度、翻转等问题

LinkedList

定义

class ListNode{
     int val;
     ListNode next;
     ListNode(int val){
          this.val=val;
          this.next=null; 
     }
}

注意事项:
1 链表题相对简单,80%以上可以采用递归和双指针来解决;
2 链表头部可能为空、被修改或者被删除的情况下,我们往往需要使用dummy, dummy.next指向头部,最终返回dummy.next即可
3 遍历联表时,应该使用:  while(cur!=null)


1 Reverse Linkedlist(出现频率最高)
思路分析

1.1 2根指针思路, dummy + cur;

1.2 cur提前存储next元素,解决了翻转时linkedlist断裂问题;

1.3 dummy用于保存遍历后的头部;

public static ListNode reverseListNonRecursive(ListNode head)
{
          // 新建一个dummy
          ListNode dummy = new ListNode(0);

           // dummy指向头部,即dummy再head前面
          dummy.next = head;

          // 边界条件;如果head或者head.next是null,直接返回head;即,没有元素或者只有一个元素;     
           if (head == null || head.next == null)
                return head;

          // 从第2个node开始遍历;原因:head.next下一步将需要设置为null
          ListNode curr = head.next;

          //head.next置为null
          head.next = null;

          //从2号node开始遍历,实施如下动作:1 curr.next前指; 2 dummy.nexe指向curr; 3 curr后移
          while (curr != null)
          {
                    //存储curr的next,为curr后移做准备
                    ListNode tmp = curr.next;

                    //1 curr.next前指
                    curr.next = dummy.next;

                    //dummy.nexe指向curr
                    dummy.next = curr;

                    //3 curr后移
                    curr = tmp;
           }
           //返回dummy.next;
           return dummy.next;
}



递归实现方式思路图(带入例子1->2->3)

public static ListNode reverseListRecursive(ListNode head)
{
  if ( head== null || head.next == null) //边界条件
                     return head;

  ListNode secondtNode = head.next;//保存状态为nextNode  
  head.next = null;

  ListNode reverseRest = reverseListRecursive( secondtNode);//通过递归翻转剩余部分链表,返回翻转后的头部为reverseRest

  secondtNode.next = head; //2号node前指1号node
  return reverseRest;  
}



-------------------------------------------------------------------------------------------------

2 合并链表(进军硅谷P102, 出现频率较高
两个有序链表, L1、L2合并后得到有序链表L3;
合并两个有序链表,返回合并后的有序表头,不允许利用额外的线性存储空间;
L1-> 5->15->NULL
L2->10->15->20->NULL


思路:
1  创建dummy, dummy.next指向新链表第一个节点;同时,为了实现遍历,也要创建cur,cur初始化为=dummy,且随着链表移动;
2  2个指针指向2个输入链表的表头,不为空的情况下,取值较小的节点放入新链表的尾部,直至两个指针至少有一个为空;
3  链表中不位空的部分放到新链表的尾部;
4  返回dummy.next

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode MergeTwoLists(ListNode l1, ListNode l2) {
         if(l1==null)
            return l2;
        if(l2==null)
            return l1;
        if(l1==null||l2==null)
            return l1==null?l2:l1;

        ListNode dummy = new ListNode(0);
        ListNode cur   = dummy;//初始化cur=dummy,

        //l1,l2任意1个不为null , 使用l1!=null,  而不是l1.next!=null;因为:要走到最后一个元素;
        while(l1 != null && l2 != null)
        {
            if(l1.val <= l2.val)
            {
                cur.next = l1;//因为cur初始化为dummy.next
                l1 = l1.next;
            }
            else
            {
                cur.next = l2;
                l2 = l2.next;
            }
            cur=cur.next;
        }

        //把剩下的list接在l3后面
        if(l1!=null)
            cur.next = l1;
        else if(l2 != null)
            cur.next=l2;

        //返回
        return dummy.next;
    }
}

注意:
1 判断链表不为空,使用l1!=null, 因为:需要走到链表最后一位;
赋值:使用cur.next=l1;  因为:cur的初始化为dummy,而dummy.next 是L3的头部;

--------------------------------------------------------------------------------------------------------------------

3 环的长度

给出一个单向链表的头指针,如果有环,则返回环的长度,否则返回零;





slow和fast两个指针扫描链表,slow每次走1步,fast每次走2步;
1 判断是否有环? 
     如果有环 ,slow和fast相遇;返回相遇点;
     如果无环,fast会遇到null;返回null;
linked list cycle1:https://leetcode.com/problems/linked-list-cycle/
linked list cycle2:   https://leetcode.com/problems/linked-list-cycle-ii/
public Node hasCycle(Node head)
{
     if(head == null)
          return null;

     Node slow=head;
     Node fast=head;

     while(fast != null && fast.next!=null && fast.next.next!=null)
     {
          //注意:先增,后比较相等;否则,首次指向head,一定会相等;
          slow=slow.next;
          fast=fast.next.next;

          if(slow==fast)
               return slow;
     }
     return null;
}


2 判断环长
     slow和fast 首次相遇,记为pos;  下次相遇时,记为Join;  pos->join,令slow走了len; fast走了2len; 环长为len;需要记忆,快慢指针两次相遇,长度为length;
//node指的是首次相遇节点
public int GetCycleLength(Node node)
{
     if(node=null)//边界条件
          return 0;

     Node slow = node;
     Node fast= node;
     length=0;
     
     while(fast!=null&&fast.next.next!=null)
     {
              slow=slow.next
              fast=fast.next.next;
              length++;
             
               if(slow==fast)
                  return length;     
     }
     return length;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值