【LeetCode】《剑指Offer》第Ⅵ篇⊰⊰⊰ 48 - 55题
文章目录
48. 最长不含重复字符的子字符串(medium)
【题目】请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
提示:
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)
【题目】我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
说明:
1
是丑数。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)
【题目】在字符串 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)
【题目】在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
限制:
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)
【题目】输入两个链表,找出它们的第一个公共节点。
如下面的两个链表**:**
在节点 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)
【题目】统计一个数字在排序数组中出现的次数。
限制:
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)
【题目】一个长度为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)
【题目】给定一棵二叉搜索树,请找出其中第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)
【题目】输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
【示例】
给定二叉树 [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)
【题目】输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过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;
}
}
🎈
创作整理不易,如果对您有帮助的话,还望多+点赞、收藏☚
欢迎在评论区留下您宝贵的建议😉😉😉