【LeetCode】《剑指Offer》第Ⅵ篇⊰⊰⊰ 48 - 55题

【LeetCode】《剑指Offer》第Ⅵ篇⊰⊰⊰ 48 - 55题

48. 最长不含重复字符的子字符串(medium)

剑指 Offer 48. 最长不含重复字符的子字符串

题目】请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

提示:

  • s.length <= 40000

示例

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3-----------------------------------------------
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1

‘【解题思路

滑动窗口

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int res = 0;
        Set<Character> set = new HashSet<>();
        for (int l = 0, r = 0; r < s.length(); r++) {
            char c = s.charAt(r);
            while (set.contains(c)) {
                set.remove(s.charAt(l++));
            }
            set.add(c);
            res = Math.max(res, r - l + 1);
        }
        return res;
    }
}

49. 丑数(medium)

剑指 Offer 49. 丑数

【题目】我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。

说明:

  1. 1 是丑数。
  2. n 不超过1690。

【示例】

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。

【解题思路】

指针,

详细丑数相关见往期博客【LeetCode】丑数(Ugly Number)☹☠☣☢☃

class Solution {
    public int nthUglyNumber(int n) {
        int[] dp = new int[n];
        int two = 0, three = 0, five = 0;
        int t = 0;
        dp[0] = 1;
        for (int i = 1; i < n; i++) {
            t = Math.min(2 * dp[two], Math.min(3 * dp[three], 5 * dp[five]));
            dp[i] = t;
            if (t == 2 * dp[two]) two++;
            if (t == 3 * dp[three]) three++;
            if (t == 5 * dp[five]) five++;
        }
        return dp[n - 1];
    }
}

50. 第一个只出现一次的字符(easy)

剑指 Offer 50. 第一个只出现一次的字符

题目】在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

限制:

0 <= s 的长度 <= 50000

示例

s = "abaccdeff"
返回 "b"
--------------------------------
s = "" 
返回 " "

解题思路

二次遍历 + 频次统计

class Solution {
    public char firstUniqChar(String s) {
        int[] count = new int[26];
        for (char c : s.toCharArray()) {
            count[c - 'a']++;
        }
        for (char c : s.toCharArray()) {
            if (count[c - 'a'] == 1) {
                return c;
            }
        }
        return ' ';
    }
}

51. 数组中的逆序对(hard)

剑指 Offer 51. 数组中的逆序对

题目】在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

限制:

0 <= 数组长度 <= 50000

示例

输入: [7,5,6,4]
输出: 5

解题思路

归并思想,

详细见往期力扣博客总结【LeetCode】﹝归并思想ி﹞逆序对、翻转对、排序链表、合并K个升序链表

class Solution {
    private static int[] aux;

    public int reversePairs(int[] nums) {
        aux = new int[nums.length];
        return sort(nums, 0, nums.length - 1);
    }

    private int sort(int[] nums, int lo, int hi) {
        if (lo >= hi) return 0;
        int m = lo + (hi - lo) / 2;
        return sort(nums, lo, m) + sort(nums, m + 1, hi) + merge(nums, lo, m, hi);
    }

    private int merge(int[] nums, int lo, int m, int hi) {
        int count = 0;
        int i = lo, j = m + 1;
        for (int k = lo; k <= hi; k++) {
            aux[k] = nums[k];
        }
        for (int k = lo; k <= hi; k++) {
            if (i > m) {
                nums[k] = aux[j++];
            } else if (j > hi) {
                nums[k] = aux[i++];
            } else if (aux[i] <= aux[j]) {
                nums[k] = aux[i++];
            }else {
                //计算逆序对数
                count += (m - i + 1);
                nums[k] = aux[j++];
            }
        }

        return count;
    }
}

52. 两个链表的第一个公共节点(easy)

剑指 Offer 52. 两个链表的第一个公共节点

题目】输入两个链表,找出它们的第一个公共节点。

如下面的两个链表**:**

在这里插入图片描述

在节点 c1 开始相交。

注意

  • 如果两个链表没有交点,返回 null.
  • 在返回结果后,两个链表仍须保持原有的结构。
  • 可假定整个链表结构中没有循环。
  • 程序尽量满足 O(n) 时间复杂度,且仅用 O(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 个节点。

解题思路

数学集合运算,

设交集链表长c,链表1除交集的长度为a,链表2除交集的长度为b,有

  • a + c + b = b + c + a
  • 若无交集,则a + b = b + a
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode pa = headA, pb = headB;
        while (pa != pb) {
            pa = pa == null ? headB : pa.next;
            pb = pb == null ? headA : pb.next;
        }
        return pa;
    }
}

参考力扣热评@宝石


53 - I. 在排序数组中查找数字 I(easy)

剑指 Offer 53 - I. 在排序数组中查找数字 I

题目】统计一个数字在排序数组中出现的次数。

限制:

0 <= 数组长度 <= 50000

示例

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2

解题思路

二分法,

由于是有序数组,很容易想到二分法,

详细二分查找知识见往期博客总结 二分查找模板(查找数、左边界、右边界)

class Solution {
    public int search(int[] nums, int target) {
        int first = 0, last = 0;
        int le = 0, ri = nums.length - 1;

        //二分查找target第一次出现的下标
        while (le <= ri) {
            int m = le + (ri - le) / 2;
            if (nums[m] < target) {
                le = m + 1;
            } else {
                ri = m - 1;
            }
        }
        first = ri + 1;

        //二分查找target最后一次出现的下标
        le = 0;
        ri = nums.length - 1;
        while (le <= ri) {
            int m = le + (ri - le) / 2;
            if (nums[m] > target) {
                ri = m - 1;
            } else {
                le = m + 1;
            }
        }
        last = le - 1;
        
        return last - first + 1;
    }
}

写完才发现第二步查找其实没必要-_-

class Solution {
    public int search(int[] nums, int target) {
        int le = 0, ri = nums.length - 1;
        //二分查找target第一次出现的下标
        while (le <= ri) {
            int m = le + (ri - le) / 2;
            if (nums[m] < target) {
                le = m + 1;
            } else {
                ri = m - 1;
            }
        }
        ri += 1;
        int count = 0;
        while (ri < nums.length && nums[ri] == target) {
            count++;
            ri++;
        }

        return count;
    }
}

53 - II. 0~n-1中缺失的数字(easy)

剑指 Offer 53 - II. 0~n-1中缺失的数字

题目】一个长度为n-1递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。

示例

输入: [0,1,3]
输出: 2
-----------------------------
输入: [0,1,2,3,4,5,6,7,9]
输出: 8

解题思路

二分查找

class Solution {
    public int missingNumber(int[] nums) {
        int le = 0, ri = nums.length - 1;
        while (le <= ri) {
            int m = le + (ri - le) / 2;
            if (nums[m] > m) {
                ri = m - 1;
            } else {
                le = m + 1;
            }
        }
        return le;
    }
}

54. 二叉搜索树的第k大节点(easy)

剑指 Offer 54. 二叉搜索树的第k大节点

题目】给定一棵二叉搜索树,请找出其中第k大的节点

限制:

1 ≤ k ≤ 二叉搜索树元素个数

示例

输入: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
输出: 4
-----------------------------------------------
输入: root = [5,3,6,2,4,null,null,1], k = 3
       5
      / \
     3   6
    / \
   2   4
  /
 1
输出: 4

解题思路

反向中序遍历

class Solution {
    int res, t;

    public int kthLargest(TreeNode root, int k) {
        res = Integer.MIN_VALUE;
        t = k;
        f(root);
        return res;
    }

    private void f(TreeNode root) {
        if (root == null) return;
        f(root.right);
        t -= 1;
        if (t == 0 && res == Integer.MIN_VALUE) {
            res = root.val;
            return;
        }
        f(root.left);
    }
}

55 - I. 二叉树的深度(easy)

剑指 Offer 55 - I. 二叉树的深度

题目】输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

示例

给定二叉树 [3,9,20,null,null,15,7]3
   / \
  9  20
    /  \
   15   7
返回它的最大深度 3

解题思路

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0;
        int deepl = maxDepth(root.left);
        int deepr = maxDepth(root.right);
        return Math.max(deepl, deepr) + 1;
    }
}

55 - II. 平衡二叉树(easy)

剑指 Offer 55 - II. 平衡二叉树

题目】输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

示例

给定二叉树 [3,9,20,null,null,15,7]
    3
   / \
  9  20
    /  \
   15   7
返回 true-----------------------------------------
给定二叉树 [1,2,2,3,3,null,null,4,4]
       1
      / \
     2   2
    / \
   3   3
  / \
 4   4
返回 false

解题思路

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return dfs(root) >= 0;
    }

    private int dfs(TreeNode root) {
        if (root == null) return 0;
        int lh = dfs(root.left);
        int rh = dfs(root.right);
        if (lh >= 0 && rh >= 0 && Math.abs(lh - rh) <= 1) {
            return Math.max(lh, rh) + 1;
        }
        return -1;
    }
}

🎈

创作整理不易,如果对您有帮助的话,还望多+点赞、收藏☚

欢迎在评论区留下您宝贵的建议😉😉😉

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值