【第三天】

链表中倒数第k个结点

题目

输入一个链表,输出该链表中倒数第k个结点。

Example

image-20230212200541254

解题

  1. 先求链表长度,然后头节点走 len - k 步(需要遍历两遍) - 注意len 要小于k才有结果的
  2. 快慢指针,快指针先走 k 步,然后快慢指针一起走(一遍遍历搞定)

代码

public ListNode FindKthToTail(ListNode head, int k) {
        if (head == null || k <= 0) {
            return null;
        }
        // fast先走k步
        ListNode fast = head;
        ListNode slow = head;

        while (k > 0) {
            // 可能k大于链表长度
            if (fast == null) return null;
            fast = fast.next;
            k--;
        }

        // fast与slow一起走
        while (fast != null) {
            slow = slow.next;
            fast = fast.next;
        }

        return slow;
    }

反转链表

题目

给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

Example

image-20230212201102176

解题

  1. 使用栈结构,先存储,然后重构链表
  2. 三指针法(也叫头插法)
  3. 递归

代码

public class Solution {
    public ListNode ReverseList(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        }

        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.next = pre;
            pre = cur;
            cur = curNext;
        }
        
        return pre;
    }
}0
public ListNode ReverseList(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        }

        ListNode newHead = ReverseList(head.next);
        head.next.next = head;
        head.next = null;
        
        return newHead;
    }

合并两个排序的链表

题目

输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。

Example

image-20230212201431927

解题

  1. 遍历两个链表(如图所示,相当于重构一个新链表)
  2. 递归(每一次递归,确定一个值)

代码

public ListNode Merge(ListNode list1, ListNode list2) {
        if (list1 == null) {
            return list2;
        }

        if (list2 == null) {
            return list1;
        }

        ListNode head = null;
        ListNode tail = null;
        if (list1.val > list2.val) {
            head = tail = list2;
            list2 = list2.next;
        } else {
            head = tail = list1;
            list1 = list1.next;
        }

        while (list1 != null && list2 != null) {
            if (list1.val > list2.val) {
                tail.next = list2;
                list2 = list2.next;
            } else {
                tail.next = list1;
                list1 = list1.next;
            }
            tail = tail.next;
        }

        tail.next = list1 == null ? list2 : list1;

        return head;
    }
public ListNode Merge(ListNode list1, ListNode list2) {
        if (list1 == null) {
            return list2;
        }

        if (list2 == null) {
            return list1;
        }

        ListNode head = null;
        if(list1.val > list2.val) {
            head = list2;
            list2 = list2.next;
        } else {
            head = list1;
            list1 = list1.next;
        }

        head.next = Merge(list1,list2);

        return head;
    }

树的子结构

题目

输入两棵二叉树A,B,判断B是不是A的子结构。(我们约定空树不是任意一个树的子结构)

Example

image-20230212201815323

解题

因为可能 B 这棵树只有一个节点,所以我们需要遍历 A 这棵树的每一个节点,就需要深度遍历 / 广度遍历,这里我使用的就是二叉树的前序遍历(从当前根节点开始判断,如果不是,就判断左数;否则,递归右数)

代码

// 比较root1是否包含root2
    public boolean isSameChild(TreeNode root1, TreeNode root2) {
        if(root2 == null) return true;  // root2树递归完了,就说明 root2是roo1的子树了
        if(root1 == null) return false;

        if (root1.val != root2.val) {
            return false;
        }

        return isSameChild(root1.left, root2.left) &&
               isSameChild(root1.right, root2.right);
    }

    public boolean HasSubtree(TreeNode root1, TreeNode root2) {
        if (root1 == null || root2 == null) return false;

        // 1. 先找起始位置
        boolean result = false;
        if (root1.val == root2.val) {
            result = isSameChild(root1, root2);
        }

        if (result != true) {
            result = HasSubtree(root1.left, root2);
        }

        if (result != true) {
            result = HasSubtree(root1.right, root2);
        }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值