4.24 技巧题
This commit is contained in:
parent
8855c19e89
commit
1cfbdd2b5c
29
src/main/java/dynamic_programming/MaxSubArray.java
Normal file
29
src/main/java/dynamic_programming/MaxSubArray.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package dynamic_programming;
|
||||||
|
/**
|
||||||
|
* 题目: 53. 最大子数组和 (maxSubArray)
|
||||||
|
* 描述:给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
|
||||||
|
* 子数组是数组中的一个连续部分。
|
||||||
|
*
|
||||||
|
示例 1:
|
||||||
|
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
|
||||||
|
输出:6
|
||||||
|
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/maximum-subarray/
|
||||||
|
*/
|
||||||
|
public class MaxSubArray {
|
||||||
|
//dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]。
|
||||||
|
public static int maxSubArray(int[] nums) {
|
||||||
|
if (nums.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int res = nums[0];
|
||||||
|
int[] dp = new int[nums.length];
|
||||||
|
dp[0] = nums[0];
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
|
||||||
|
res = Math.max(res, dp[i]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
40
src/main/java/dynamic_programming/MaxUncrossedLines.java
Normal file
40
src/main/java/dynamic_programming/MaxUncrossedLines.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package dynamic_programming;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 题目: 1035. 不相交的线 (maxUncrossedLines)
|
||||||
|
* 描述:在两条独立的水平线上按给定的顺序写下 nums1 和 nums2 中的整数。
|
||||||
|
* 现在,可以绘制一些连接两个数字 nums1[i] 和 nums2[j] 的直线,这些直线需要同时满足:
|
||||||
|
* nums1[i] == nums2[j]
|
||||||
|
* 且绘制的直线不与任何其他连线(非水平线)相交。
|
||||||
|
* 请注意,连线即使在端点也不能相交:每个数字只能属于一条连线。
|
||||||
|
*
|
||||||
|
* 以这种方法绘制线条,并返回可以绘制的最大连线数。
|
||||||
|
*
|
||||||
|
示例 1:
|
||||||
|
输入:nums1 = [1,4,2], nums2 = [1,2,4]
|
||||||
|
输出:2
|
||||||
|
解释:可以画出两条不交叉的线,如上图所示。
|
||||||
|
但无法画出第三条不相交的直线,因为从 nums1[1]=4 到 nums2[2]=4 的直线将与从 nums1[2]=2 到 nums2[1]=2 的直线相交。
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/uncrossed-lines/
|
||||||
|
*/
|
||||||
|
//转为求最长子序列
|
||||||
|
public class MaxUncrossedLines {
|
||||||
|
public int maxUncrossedLines(int[] nums1, int[] nums2) {
|
||||||
|
int len1 = nums1.length;
|
||||||
|
int len2 = nums2.length;
|
||||||
|
int[][] dp = new int[len1 + 1][len2 + 1];
|
||||||
|
|
||||||
|
for (int i = 1; i <= len1; i++) {
|
||||||
|
for (int j = 1; j <= len2; j++) {
|
||||||
|
if (nums1[i - 1] == nums2[j - 1]) {
|
||||||
|
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||||
|
} else {
|
||||||
|
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[len1][len2];
|
||||||
|
}
|
||||||
|
}
|
84
src/main/java/trick/FindDuplicate.java
Normal file
84
src/main/java/trick/FindDuplicate.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package trick;
|
||||||
|
/**
|
||||||
|
* 题目: 287. 寻找重复数 (findDuplicate)
|
||||||
|
* 描述:给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
|
||||||
|
* 假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
|
||||||
|
* 你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
|
||||||
|
*
|
||||||
|
示例 1:
|
||||||
|
输入:nums = [1,3,4,2,2]
|
||||||
|
输出:2
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/find-the-duplicate-number/
|
||||||
|
*/
|
||||||
|
//不会
|
||||||
|
public class FindDuplicate {
|
||||||
|
/**“按位统计”+位运算
|
||||||
|
* 对于答案 x(重复的数),它在二进制的某一位上是 1,那么这一位上,整个数组里置 1 的次数,一定比从 1 到 n 的所有数里置 1 的次数要多(多出的部分就是重复的那一位贡献的)。
|
||||||
|
* 所以我们可以:
|
||||||
|
* 对 0..31 每一位,遍历 nums 数组,统计该位上多少个 1:countNums。
|
||||||
|
* 同时统计 1 到 n 这 n 个数在该位上多少个 1:countRange。
|
||||||
|
* 如果 countNums > countRange,说明重复的数字在这一位上是 1,否则是 0。
|
||||||
|
* 最后把所有位拼起来,就是答案。
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findDuplicate(int[] nums) {
|
||||||
|
int n = nums.length - 1; // nums 中的数都在 [1..n] 里
|
||||||
|
int duplicate = 0;
|
||||||
|
// 对 0..31 位都做一次统计
|
||||||
|
for (int bit = 0; bit < 32; bit++) {
|
||||||
|
int mask = 1 << bit;
|
||||||
|
int countNums = 0, countRange = 0;
|
||||||
|
// 统计数组里这一位的 1 的个数
|
||||||
|
for (int x : nums) {
|
||||||
|
if ((x & mask) != 0) countNums++;
|
||||||
|
}
|
||||||
|
// 统计 [1..n] 里这一位的 1 的个数
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
if ((i & mask) != 0) countRange++;
|
||||||
|
}
|
||||||
|
// 如果数组中多出来,说明重复数这一位是 1
|
||||||
|
if (countNums > countRange) {
|
||||||
|
duplicate |= mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数值范围
|
||||||
|
* 因为 nums 大小是 n+1,且所有元素都在 [1..n] 里,必有重复。我们把搜索范围定在 low = 1 到 high = n。
|
||||||
|
*
|
||||||
|
* 计数判定
|
||||||
|
* 对中点 mid = (low + high) / 2,遍历一次数组,统计有多少元素 ≤ mid,记为 cnt。
|
||||||
|
*
|
||||||
|
* 如果 cnt > mid,说明在 [1..mid] 里「装不下」这么多数(因为最多只有 mid 个不同的数),重复值必然落在这一半区间,于是令 high = mid。
|
||||||
|
* 否则,说明重复值在右边区间,令 low = mid + 1。
|
||||||
|
* 结束条件
|
||||||
|
* 当 low == high 时,区间只剩一个数,它就是答案。
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findDuplicate1(int[] nums) {
|
||||||
|
int n = nums.length - 1; // 数值范围在 [1..n]
|
||||||
|
int low = 1, high = n;
|
||||||
|
while (low < high) {
|
||||||
|
int mid = low + (high - low) / 2;
|
||||||
|
// 统计 nums 中有多少个数 <= mid
|
||||||
|
int cnt = 0;
|
||||||
|
for (int x : nums) {
|
||||||
|
if (x <= mid) cnt++;
|
||||||
|
}
|
||||||
|
// 如果“数量”超过了 mid,说明重复值在 [low..mid]
|
||||||
|
if (cnt > mid) {
|
||||||
|
high = mid;
|
||||||
|
} else {
|
||||||
|
low = mid + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// low == high
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
src/main/java/trick/NextPermutation.java
Normal file
47
src/main/java/trick/NextPermutation.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package trick;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 题目: 31. 下一个排列 (nextPermutation)
|
||||||
|
* 描述:整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
|
||||||
|
*
|
||||||
|
* 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
|
||||||
|
* 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
|
||||||
|
*
|
||||||
|
* 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
|
||||||
|
* 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
|
||||||
|
* 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
|
||||||
|
* 给你一个整数数组 nums ,找出 nums 的下一个排列。
|
||||||
|
*
|
||||||
|
* 必须 原地 修改,只允许使用额外常数空间。
|
||||||
|
*
|
||||||
|
示例 1:
|
||||||
|
输入:nums = [1,2,3]
|
||||||
|
输出:[1,3,2]
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/next-permutation/
|
||||||
|
*/
|
||||||
|
public class NextPermutation {
|
||||||
|
public void nextPermutation(int[] nums) {
|
||||||
|
int n = nums.length;
|
||||||
|
// 1. 从右向左,找到第一个「前驱/枢轴」i,使得 nums[i] < nums[j](j>i)
|
||||||
|
// 这样 nums[i+1..n-1] 一定是非增的
|
||||||
|
for (int i = n - 2; i >= 0; i--) {
|
||||||
|
// 2. 对于找到的 i,再从右向左找第一个 nums[j] > nums[i]
|
||||||
|
for (int j = n - 1; j > i; j--) {
|
||||||
|
if (nums[j] > nums[i]) {
|
||||||
|
// 3. 交换枢轴 i 和后缀中刚好比它大的那个 j
|
||||||
|
int tmp = nums[i];
|
||||||
|
nums[i] = nums[j];
|
||||||
|
nums[j] = tmp;
|
||||||
|
// 4. 将 i+1 到末尾这段降序数组,升序排列,得到下一个最小排列
|
||||||
|
Arrays.sort(nums, i + 1, n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果整个数组都是降序的,说明已经是最大排列了,直接变成最小排列(全升序)
|
||||||
|
Arrays.sort(nums);
|
||||||
|
}
|
||||||
|
}
|
40
src/main/java/trick/SortColors.java
Normal file
40
src/main/java/trick/SortColors.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package trick;
|
||||||
|
/**
|
||||||
|
* 题目: 75. 颜色分类 (singleNumber)
|
||||||
|
* 描述:给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
|
||||||
|
* 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
|
||||||
|
* 必须在不使用库内置的 sort 函数的情况下解决这个问题。
|
||||||
|
*
|
||||||
|
示例 1:
|
||||||
|
输入:nums = [2,0,2,1,1,0]
|
||||||
|
输出:[0,0,1,1,2,2]
|
||||||
|
|
||||||
|
* 链接:https://leetcode.cn/problems/sort-colors/
|
||||||
|
*/
|
||||||
|
public class SortColors {
|
||||||
|
void swap(int[]a,int i,int j){
|
||||||
|
int temp=a[i];
|
||||||
|
a[i]=a[j];
|
||||||
|
a[j]=temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [0……left-1] 全是 0
|
||||||
|
* [left……i-1] 全是 1
|
||||||
|
* [i……right] 未知区
|
||||||
|
* [right+1……n-1] 全是 2
|
||||||
|
* @param nums
|
||||||
|
*/
|
||||||
|
public void sortColors(int[] nums) {
|
||||||
|
int left = 0, i = 0, right = nums.length - 1;
|
||||||
|
while (i <= right) {
|
||||||
|
if (nums[i] == 0) {
|
||||||
|
swap(nums, left++, i++);
|
||||||
|
} else if (nums[i] == 2) {
|
||||||
|
swap(nums, i, right--);
|
||||||
|
} else { // nums[i] == 1
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/test/java/trick/FindDuplicateTest.java
Normal file
15
src/test/java/trick/FindDuplicateTest.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package trick;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class FindDuplicateTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findDuplicate() {
|
||||||
|
FindDuplicate findDuplicate = new FindDuplicate();
|
||||||
|
int[]a={3,1,3,4,2};
|
||||||
|
findDuplicate.findDuplicate(a);
|
||||||
|
}
|
||||||
|
}
|
18
src/test/java/trick/SortColorsTest.java
Normal file
18
src/test/java/trick/SortColorsTest.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package trick;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class SortColorsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sortColors() {
|
||||||
|
SortColors solution = new SortColors();
|
||||||
|
int[]nums = {1,2,0};
|
||||||
|
solution.sortColors(nums);
|
||||||
|
System.out.println(Arrays.toString(nums));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user