剑指offer 链表相关简单题目如下
接下来全部用递归来解答这些题目 , 语言选择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 开始相交
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构
示例 1:
输入: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:
输入: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:
输入: 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. 两个链表的第一个公共节点
输入两个链表,找出它们的第一个公共节点。
如下面的两个链表
在节点 c1 开始相交。
示例 1:
输入: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;
}
}