代码随想录第一周扩展题总结
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n)
的算法。
输入: nums = [1,3,5,6], target = 5 输出: 2
算法 二分查找
class Solution { public int searchInsert(int[] nums, int target) { int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] > target) { right = mid - 1; } else { left = mid + 1; } } return right + 1; } }
34. 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
确定好:计算出来的右边界是不包含target的右边界,左边界同理。
class Solution { public int[] searchRange(int[] nums, int target) { int first = firstPost(nums, target); int last = lastPost(nums, target); return new int[]{first, last}; } private int firstPost(int[] nums, int target) { if (nums == null || nums.length == 0) return -1; int left = 0; int right = nums.length - 1; while (left < right - 1) { int mid = left + (right - left) / 2; if (nums[mid] < target) { left = mid; } else { right = mid; } } if (nums[left] == target) { return left; } if (nums[right] == target) { return right; } return -1; } private int lastPost (int[] nums, int target) { if (nums == null || nums.length == 0) { return -1; } int left = 0; int right = nums.length - 1; while (left + 1 < right) { int mid = left + (right - left) / 2; if (target >= nums[mid]) { left = mid; } else { right = mid; } } if (nums[right] == target) { return right; } if (nums[left] == target) { return left; } return -1; } }
69. x 的平方根
给你一个非负整数 x
,计算并返回 x
的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5)
或者
算法 利用二分搜索 搜索范围0 ~ x
class Solution { public int mySqrt(int x) { long left = 1; long right = x; while (left < right - 1) { long mid = left + (right - left) - 1; if (mid * mid <= x) { left = mid; } else { right = mid; } } if (right * right <= x) return (int)right; return (int)left; } }
367. 有效的完全平方数
给你一个正整数 num
。如果 num
是一个完全平方数,则返回 true
,否则返回 false
。
完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。
不能使用任何内置的库函数,如 sqrt
。
class Solution { public boolean isPerfectSquare(int num) { int left = 1; int right = num; while (left < right - 1) { long mid = left + (right - left) / 2; if (mid * mid == num) { return true; } else if (mid * mid < num) { left = (int)mid; } else { right = (int)mid; } } if (left * left == num) return true; if (right * right == num) return true; return false; } }
26. 删除有序数组中的重复项
给你一个 升序排列 的数组 nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k
个元素,那么 nums
的前 k
个元素应该保存最终结果。
将最终结果插入 nums
的前 k
个位置后返回 k
。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
输入:nums = [1,1,2] 输出:2, nums = [1,2,_]
class Solution { public int removeDuplicate(int[] nums) { int n = nums.length; int slow = 1; int fast = 1; while (fast < n) { if (nums[fast] != nums[fast - 1]) { nums[slow] = numst[fast]; slow++; } fast++; } return fast; } }
283.移动零
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
i = 0, j = 0 i != 0 交换nums[i], nums[j]
class Solution { public void moveZeroes(int[] nums) { for (int i = 0, j = 0; i < nums.length; i++) { if (nums[i] != 0) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; j++; } } } }
844. 比较含退格的字符串
给定 s
和 t
两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true
。#
代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空
class Solution { public boolean backspaceCompare(String s, String t) { int i = s.length() - 1; int j = t.length() - 1; int skipA = 0; int skipB = 0; while (i >= 0 || j >= 0) { while (i >= 0) { if (s.charAt(i) == '#') { skipA++; i--; } else if (skipA > 0) { skipA--; i--; } else { break; } } while (j >= 0) { if (t.charAt(j) == '#') { skipB++; j--; } else if (skipB > 0) { skipB--; j--; } else { break; } } if (i >= 0 && j >= 0) { if (s.charAt(i) != t.charAt(j)) { return false; } } else { if (i >= 0 || j >= 0) { return false; } } i--; j--; } return true; } }
904. 水果成篮
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits
表示,其中 fruits[i]
是第 i
棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
- 你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
- 你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
- 一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits
,返回你可以收集的水果的 最大 数目。
我们每次将 right\textit{right}right 移动一个位置,并将 fruits[right]\textit{fruits}[\textit{right}]fruits[right] 加入哈希表。如果此时哈希表不满足要求(即哈希表中出现超过两个键值对),那么我们需要不断移动 left\textit{left}left,并将 fruits[left]\textit{fruits}[\textit{left}]fruits[left] 从哈希表中移除,直到哈希表满足要求为止。
class Solution { public int totalFruit(int[] fruits) { int n = fruits.length; Map<Integer, Integer> cnt = new HashMap<>(); int left = 0, ans = 0; for (int right = 0;right < n; right++) { cnt.put(fruits[right], cnt.getOrDefault(fruits[right], 0) + 1); while (cnt.size() >2) { cnt.put(fruits[left], cnt.get(fruits[left]) - 1); if (cnt.get(fruits[left]) == 0) { cnt.remove(fruits[left]); } ++left; } ans = Math.max(ans, right - left + 1); } return ans; } }
76. 最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
class Solution { public String minWindow(String s, String t) { int[] cnt = new int[128]; for (char c : t.toCharArray()) { cnt[c]++; } int total = t.length(); int from = 0; int min = Integer.MAX_VALUE; for (int i = 0, j = 0; i < s.length(); i++) { if ( cnt[s.charAt(i)]-- > 0 ) total--; while (total == 0) { if (i - j + 1 < min) { min = i - j + 1; from = j; } if (++cnt[s.charAt(j++)] > 0) total++; } } return min == Integer.MAX_VALUE ? "" : s.substring(from, from + min); } }