【剑指offer】从尾到头打印链表+链表中倒数第k个节点

🔥题目

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

输入:1 → 3 → 2 → 4
输出: [4, 2, 3, 1]

☘️解析

立即想到3种思路

1)递归打印
2)借助辅助栈迭代打印
3)扫描两次,第一次扫描得到链表长度。第一次扫描将元素落位到数组

🧊代码
class Solution1 {
    public int[] reversePrint(ListNode head) {
    	// 递归打印
        printList(head);
        int[] res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
        return res;
    }

    private List<Integer> list = new ArrayList<>();

    private void printList(ListNode node) {
        if (node == null) {
            return;
        }
        printList(node.next);
        list.add(node.val);
    }
}

class Solution2 {
    public int[] reversePrint(ListNode head) {
    	// 借助辅助栈迭代打印
        Deque<Integer> stack = new LinkedList<>();
        while (head != null) {
            stack.push(head.val);
            head = head.next;
        }  
        int[] res = new int[stack.size()];
        for (int i = 0; i < res.length; i++) {
            res[i] = stack.pop();
        }
        return res;
    }
}

class Solution3 {
    public int[] reversePrint(ListNode head) {
    	// 扫描两次,第一次扫描得到链表长度。第一次扫描将元素落位到数组
        ListNode node = head;
        // 第一次
        int len = 0;
        while (node != null) {
            node = node.next;
            len++;
        }
        // 第二次
        int[] res = new int[len];
        int index = len - 1;
        node = head;
        while (node != null) {
            res[index--] = node.val;
            node = node.next;
        }
        return res;
    }
}
🌸补充

三种思路的是时间复杂度都是O(n)。

但是对比效率,两次扫描效率最高,使用辅助栈效率次之,递归效率最低。

 
 
 
 
 

🔥题目

输入一个链表,输出该链表中倒数第k个节点。
为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

输入:1 → 2 → 3 → 4 → 5,k=2
输出:4

☘️解析

解法一:两次遍历

第一次遍历得到链表长度len,第二次遍历得到正数第(len-k+1)个节点,即为倒数第k个节点。

解法二:快慢指针

先让快指针走k步,再让快慢指针同步一起走,快指针走到头(null)时,慢指针即为倒数第k个节点。

🧊代码

解法一:两次遍历

class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        int len = 0;
        ListNode cur = head;
        while (cur != null) {
            cur = cur.next;
            len++;
        }
        cur = head;
        while (len - k > 0) {
            cur = cur.next;
            len--;
        }
        return cur;
    }
}

解法二:快慢指针

class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode slow = head;
        ListNode fast = head;
        while (k > 0) {
            fast = fast.next;
            k--;
        }
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}
🌸补充

两次遍历是非常朴素的思路,快慢指针是非常经典的思路。推荐后者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值