2021-6-13-剑指笔记01

Posted 轻舟一曲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-6-13-剑指笔记01相关的知识,希望对你有一定的参考价值。

笔记01

_11_返回倒数第k个节点

package LeetCode._面试经典.笔记01;

public class _11_返回倒数第k个节点 

    public class ListNode 
        int val;
        ListNode next;
        ListNode(int x)  val = x; 
    

    /*
    1.递归:代码简洁但是需要占用O(N)的空间
    2.迭代:代码稍微复杂一点但是效率快
    * */
    public int K=0;
    public int value=0;
    public int kthToLast(ListNode head, int k) 
       K=k;
       nthToLast(head);
       return value;
    
    //递归每次返回该节点的下标(tip:最后1个为倒数第1个)
    public int nthToLast(ListNode node)
        if (node==null) return 0;
        int l=nthToLast(node.next)+1;
        if (l==K) value=node.val;
        return l;
    

    //快慢指针
    public int kthToLast02(ListNode head, int k) 
        if (head==null) return 0;
        ListNode slow=head;
        ListNode fast=head;
        while (k>0&&fast!=null)//最后fast肯定到null所以需要多走1步
            fast=fast.next;
            k--;
        
        if (k!=0) return 0;//不合法的k
        while (fast!=null)
            slow=slow.next;
            fast=fast.next;
        
        return slow.val;
    


_12_删除链表中间节点

package LeetCode._面试经典.笔记01;

import org.junit.Test;

import java.util.Random;

public class _12_删除链表中间节点 

    public class ListNode 
        int val;
        ListNode next;
        ListNode(int x)  val = x; 
    
    /*
    中间节点:除去首尾节点外都叫中间节点,只能访问删除的的节点
    tips:若待删除的是尾结点,该题无解,面试的时候应该给面试官指出
    将其为null ? 很明显这就是对指针的不理解了,你置null只是将node置null,却并未将前驱节点的next置null,其还是只想该块内存额
    * */

    public void deleteNode(ListNode node) 
        if (node==null) return;
        if (node.next==null) 
            System.out.println("尾结点:"+node.val);
            node.val=-1;
            return;
        
        node.val=node.next.val;
        node.next=node.next.next;
    

    @Test
    public void test()
        //[a,b] random(b-a)+a
        ListNode head=new ListNode(1);
        ListNode n2=new ListNode(2);
        ListNode n3=new ListNode(3);
        ListNode n4=new ListNode(4);
        head.next=n2;
        n2.next=n3;
        n3.next=n4;
        deleteNode(n4);
        print(head);
    
    public void print(ListNode node)
        ListNode p=node;
        while (p!=null)
            System.out.println(p.val);
            p=p.next;
        
    

_13_分割链表

package LeetCode._面试经典.笔记01;

import org.junit.Test;

public class _13_分割链表 
    public class ListNode 
        int val;
        ListNode next;
        ListNode(int x)  val = x; 
    

    /*
    询问如果不考虑"稳定性":原来的顺序不变-->1个链表:头插+尾插
    考虑:2个链表
    * */
    public ListNode partition01(ListNode head, int x) 
       if (head==null) return null;
       ListNode lowS=new ListNode(-1);
       ListNode lowL=lowS;

       ListNode highS=new ListNode(-1);
       ListNode highL=highS;

       ListNode p=head;
       while (p!=null)//保证losS或highS最后1个不为null
           if (p.val<x)
               lowL.next=p;
               lowL=lowL.next;
           
           else 
               highL.next=p;
               highL=highL.next;
           
           p=p.next;
       
       //避免出现环
       lowL.next=null;
       highL.next=null;
       lowL.next=highS.next;
       return lowS.next;
    

    //不考虑稳定性,利用现有节点进行头插尾插法,更简洁代码
    //左边部分<x 右边部分>=x
    public ListNode partition(ListNode head, int x)
        if (head==null) return null;
        ListNode S=head;
        ListNode L=head;
        ListNode P=head.next;
        while (P!=null)
            ListNode next=P.next;
            if (P.val<x)
                P.next=S;//p.next断开,下面就用不到了
                S=P;
            
            else 
                L.next=P;
                L=P;
            
            P=next;
        
        L.next=null;
        return  S;
    

    @Test
    public void  test()
        ListNode n1=new ListNode(1);
        ListNode n2=new ListNode(4);
        ListNode n3=new ListNode(3);
        ListNode n4=new ListNode(2);
        ListNode n5=new ListNode(5);
        ListNode n6=new ListNode(2);
        n1.next=n2;
        n2.next=n3;
        n3.next=n4;
        n4.next=n5;
        n5.next=n6;

        ListNode res=partition(n1,3);
    


_14_链表求和

package LeetCode._面试经典.笔记01;

public class _14_链表求和 
     public class ListNode 
           int val;
           ListNode next;
           ListNode(int x)  val = x; 
     
    /*
    首先回顾一下加法:
       6 1 7
    +  2 5 9

    可用递归实现,注意短链表的空指针
    * */
    public ListNode addTwoNumbers01(ListNode l1, ListNode l2) 
        return nextList(l1,l2,0);
    
    public ListNode nextList(ListNode l1,ListNode l2,int carry)
        if (l1==null&&l2==null&&carry==0) return null;
        int sum=carry;
        if (l1!=null) sum+=l1.val;
        if (l2!=null) sum+=l2.val;
        ListNode res=new ListNode(sum%10);//先序遍历
        res.next=nextList(l1==null?null:l1.next,l2==null?null:l2.next,sum/10);
        return res;
    

    /*
    进阶:整数正向存储
    因为需要配对,所以需要先补0
    * */

    public class PartialSum//封装类
        public ListNode sum=null;
        public int carry=0;
    

    //两个节点相加得到一个封装加数节点PartialSum,再往前传递即可
    PartialSum addHelper(ListNode l1,ListNode l2)
        if (l1==null&&l2==null)
            return new PartialSum();
        
        PartialSum sumHelper=addHelper(l1.next,l2.next);
        //得到l1.next,l2.next的加数类,直接拿加数类的节点即可
        //构造当前加数类的节点
        int val=sumHelper.carry+l1.val+l2.val;
        ListNode node=new ListNode(val%10);//当前加数节点
        if (sumHelper.sum!=null)
            node.next=sumHelper.sum;
        sumHelper.carry=val/10;
        return sumHelper;//最后返回的是一个加数节点和进位
    


    public ListNode addTwoNumbers(ListNode l1, ListNode l2) 
        if (l1==null||l2==null) return l1==null?l2:l1;
        int count1=0;
        ListNode p1=l1;
        while (p1!=null)
            count1++;
            p1= p1.next;
        
        int count2=0;
        ListNode p2=l1;
        while (p2!=null)
            count2++;
            p2= p2.next;
        
        if (count1<count2) return addTwoNumbers(l2,l2);
        //保证l1最长
        int diff=count1-count2;
        ListNode head2=new ListNode(0);
        ListNode p=head2;
        for (int i=1;i<=diff;i++)
            ListNode node=new ListNode(0);
            p.next=node;
            p=node;
        
        if (diff!=0)
            p.next=l2;
            l2=head2;
        
        PartialSum res=addHelper(l1,l2);
        if (res.carry==0)
             return res.sum;
        else 
            ListNode node=new ListNode(res.carry);//当前加数节点
            if (res.sum!=null)
                node.next=res.sum;
            return node;
        
    





_15_回文链表

编写一个函数,检查输入的链表是否是回文的。

示例 1:

输入: 1->2
输出: false
示例 2:

输入: 1->2->2->1
输出: true

进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

package LeetCode._面试经典.笔记01;

import org.junit.Test;

import java.util.ArrayDeque;

public class _15_回文链表 

        public class ListNode 
            int val;
            ListNode next;
            ListNode(int x)  val = x; 
        

        //方法1:先将链表反转(头插),然后比较前半部分   O(N)  O(N)
        public boolean isPalindrome01(ListNode head) 
              if (head==null) return true;
              ListNode node=getReverse(head);
              return isReverse(head,node);
        
        public ListNode getReverse(ListNode head)
            ListNode p=head;
            ListNode r=null;
            while (p!=null)
                ListNode node=new ListNode(p.val);
                node.next=r;
                r=node;
                p=p.next;
            
            //最后一个节点为头节点
            return r;

        
        public boolean isReverse(ListNode l1,ListNode l2)
            ListNode p1=l1;
            ListNode p2=l2;
            while (p1!=null&&p2!=null)
                if (p1.val!=p2.val) return false;
                p1=p1.next;
                p2=p2.next;
            
            return true;
        

        //---------------------------------------------------------------
        //方法2:迭代法,利用栈+快慢指针  O(N)  O(N)
        public boolean isPalindrome02(ListNode head) 
            if (head==null) return true;

            ListNode slow=head;
            ListNode fast=head;
            ArrayDeque<Integer> deque = new ArrayDeque<>();
            while (fast!=null&&fast.next!=null)
                deque.addFirst(slow.val);
                slow=slow.next;
                fast=fast.next.next;
            
            //因为有奇数个节点,所以跳过中间节点
            if (fast!=null) slow=slow.next;
            while (slow!=null)
                if (deque.removeFirst()!=slow.val) return false;
                slow=slow.next;
            
            return true;
        

       //---------------------------------------------------------------
       //方法3:递归,使用一个封装类
       class Result
            ListNode node;
            boolean result;

           public Result(ListNode node, boolean result) 
               this.node = node;
               this.result = result;
           
       
       public boolean isPalindrome(ListNode head)
          int len=0;
          ListNode p=head;
          while (p!=null)
              len++;
              p=p.next;
          
           Result reverse = isReverse(head, len);
          return  reverse.result;
       
       //封装类的意思是返回 内序列的比对结果以及下次比较的内序列的最后1个节点
       Result isReverse(ListNode head,int len)

            if (head==null||len<=0)//偶数个节点
                return new Result(head,true);
            
            else if (len==1)//奇数个节点
                return new Result(head.next,true);
            

            Result res=isReverse(head.next,len-2);
            if (!res.result||res.node==null) return res;//向上传递失败信息
            res.result=(head.val==res.node.val);
            res.no

以上是关于2021-6-13-剑指笔记01的主要内容,如果未能解决你的问题,请参考以下文章

2021-6-13-剑指笔记01

2021-6-13-剑指笔记01

[Unity学习笔记:FPS游戏制作]角色的移动,旋转与推进上升————(2021.6.13学习笔记)

2021/6/13 刷题笔记括号生成与回溯法(深度优先遍历)

2021-6-4剑指笔记01

[Unity学习笔记:FPS游戏制作] 发射子弹————(2021.6.20学习笔记)