剑指Offer 链表简单题全递归解法

168 阅读5分钟

剑指offer 链表相关简单题目如下 image.png 接下来全部用递归来解答这些题目 , 语言选择Kotlin , 没有Kotlin 使用 Java

剑指 Offer 06. 从尾到头打印链表

输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 示例 1:

输入head = [1,3,2]
输出:[2,3,1]

class Solution {
      fun reversePrint(head: ListNode?): IntArray {
            val list = mutableListOf<Int>()
            recurve(head ,list)
            return list.toIntArray()
        }

        private fun recurve(head: ListNode?, list :MutableList<Int>){
            if(head==null){
                return
            }
            recurve(head.next ,list);
            list.add(head.`val`)
        }
}

先递到链表的尾部(调用recurve), 然后归的时候list.add就行了

剑指 Offer 18. 删除链表的节点

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 返回删除后的链表的头节点。 示例 1:

输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

示例 2:

输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

class Solution {
    fun deleteNode(head: ListNode?, `val`: Int): ListNode? {
      if(head == null)return null
      if(head.`val`==`val`)return head.next
      else{
          head.next = deleteNode(head.next,`val`)
      }
       return head;
    }
}

如果head.val==val 返回 head.next ,删除此 head , 或者head.next 指向下一次递归的结果 , 如果 if(head == null) 没找到删除的节点 或者 if(head.val==val) 找到了要删除的节点 , 递归结束

剑指 Offer 22. 链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。 例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。
示例:

给定一个链表: 1->2->3->4->5, 和 _k _= 2.
返回链表 4->5.

class Solution {
    var curIndex = 1;
    fun getKthFromEnd(head: ListNode?, k: Int): ListNode? {
        if(head ==null)return head
       var result= getKthFromEnd(head.next , k)
        if(curIndex++ == k){
            result = head
        }
        return result

    }
}

先递到链表尾节点 , 然后归的时候 curIndex++ , 如果(curIndex++ == k) 记录结果 result , 完成递归之后返回

剑指 Offer 24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。 示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

class Solution {
    fun reverseList(head: ListNode?): ListNode? {
        if(head?.next ==null){return head}
        var result=  reverseList(head.next);
        head.next.next = head ;
        head.next= null;
        return result;

    }
}

先递到链表尾节点 , 然后归的时候 head.next.next = head ; head.next= null;

剑指 Offer 25. 合并两个排序的链表

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1:

输入1->2->4, 1->3->4
输出1->1->2->3->4->4

class Solution {
    fun mergeTwoLists(l1: ListNode?, l2: ListNode?): ListNode? {
        if(l1 ==null)return l2
        if(l2==null)return l1
        if(l1.`val`<= l2.`val`){
            l1.next = mergeTwoLists(l1.next,l2);    
            return l1;
        }else{
               l2.next = mergeTwoLists(l1,l2.next);
            return l2;
        }

    }
}

剑指 Offer II 023. 两个链表的第一个重合节点

给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。
如果两个链表没有交点,返回 null 。
图示两个链表在节点 c1 开始相交 image.png 题目数据 保证 整个链式结构中不存在环。 注意,函数返回结果后,链表必须 保持其原始结构 示例 1: image.png

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 输出:Intersected at '8' 解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2: image.png

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

class Solution {
    fun getIntersectionNode(headA:ListNode?, headB:ListNode?):ListNode? {
         var headA =headA
         var headB =headB
        var aLen =getListLength(headA)
        var bLen =getListLength(headB)
        var absDiv =Math.abs(aLen-bLen)
        while(absDiv>0){
            if(aLen>bLen){
                headA=headA?.next
            }else{
                headB=headB?.next
            }
            absDiv--
        }
        return recurveList(headA ,headB)
        
    }

   fun recurveList(headA:ListNode?, headB:ListNode?):ListNode?{
       if(headA ==null && headB ==null){return null}
     var res=  recurveList(headA?.next , headB?.next)
     if(headA ==headB){
         res =headA
     }
     return res;
   }

   fun getListLength(head:ListNode?):Int{
       var head =head
        var len =0
        while(head !=null){
           head  =head?.next
           len++
        }
        return len
    }
}

先获取链表的长度 , 从两链表相同长度使用递归

剑指 Offer II 027. 回文链表

给定一个链表的 **头节点 head ,**请判断其是否为回文链表。 如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。 示例 1: image.png

输入: head = [1,2,3,3,2,1] 输出: true

class Solution {
    var head :ListNode?=null
    fun isPalindrome(head: ListNode?): Boolean {
        if(head?.next ==null)return true
        this.head=head
        return recurveCheck(head);
    }
    fun recurveCheck(head1: ListNode?):Boolean {
        if(head1==null)return true
        var ret= recurveCheck(head1?.next)
        if(ret){
        if(head1?.`val` != head?.`val`){
         ret =false
        }
       }      
        head=head?.next   
        return ret;   
   }
}

先保存链表头结点 , 然后递归到链表尾部 , 归的时候如果 (head1?.val != head?.val) 保存ret = false , 头结点 head=head?.next

面试题52. 两个链表的第一个公共节点

输入两个链表,找出它们的第一个公共节点。 如下面的两个链表 image.png 在节点 c1 开始相交。 示例 1: image.png

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

这道题和 剑指 Offer II 023. 两个链表的第一个重合节点 类似 , 没有kotlin , 附上java 解法

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //先统计链表长度
        int aLength =getListLength(headA);
        int bLength =getListLength(headB);
        int dValue =aLength-bLength;
        int sAbsValue =Math.abs(dValue);
         while(sAbsValue>0){
             //A长B短 , A先跑
             if(dValue>0){
                   headA=headA.next;
             }else{
                 headB=headB.next;
             }
               sAbsValue--;
           }
         return  recurveCheck(headA,headB);
     
    }

ListNode resNode;
  private ListNode recurveCheck(ListNode headA, ListNode headB){
      if(headA==null||headB==null){return null;}
      recurveCheck(headA.next ,headB.next);
      if(headA ==headB){
          resNode= headA;
      }
      return resNode;

  }
  private int getListLength(ListNode head){
       var res = 0;
       while(head!=null){
           res++;
           head =head.next;
       }
       return res;

   }

}