No.1 人口最多的年份
解题思路
数据范围比较小,直接枚举统计即可。
代码展示
public int maximumPopulation(int[][] logs) {
int[] population = new int[2051];
for (var log : logs) {
for (int i = log[0]; i < log[1]; i++) {
population[i]++;
}
}
int res = 1950;
for (int i = 1951; i <= 2050; i++) {
if (population[i] > population[res]) {
res = i;
}
}
return res;
}
}
No.2下标对中的最大距离
解题思路
输入的两个数组都是单调的,可以使用双指针。
代码展示
public int maxDistance(int[] nums1, int[] nums2) {
int n = nums1.length, m = nums2.length;
int res = 0;
for (int i = 0, j = -1; i < n; i++) {
while (j + 1 < m && nums1[i] <= nums2[j + 1]) {
j++;
}
res = Math.max(res, j - i);
}
return res;
}
}
No.3 子数组最小乘积的最大值
解题思路
单调栈的变形,可以先去做一下最大矩形回顾一下单调栈。
当子数组的最小值确定时,肯定是数组越长越好,所以我们需要知道每个元素左右第一个比它小的元素的位置,以在枚举每个元素作为子数组最小值时,这个子数组最大可以是多大。
代码展示
int getMinSwaps(String num, int k) {
char[] nums = num.toCharArray();
char[] target = num.toCharArray();
for (int i = 0; i < k; i++) {
nextPermutation(target);
}
int ans = 0, n = nums.length;
for (int i = 0; i < n; ++i) {
if (nums[i] != target[i]) {
int j = i + 1;
while (j < n && nums[j] != target[i]) {
j++;
}
for (; j > i; j--) {
swap(nums, j - 1, j);
ans++;
}
}
}
return ans;
}
public void nextPermutation(char[] nums) {
for (int i = nums.length - 2; i >= 0; i--) {
if (nums[i] < nums[i + 1]) {
for (int j = nums.length - 1; j > i; j--) {
if (nums[i] < nums[j]) {
swap(nums, i, j);
reverse(nums, i + 1, nums.length - 1);
return;
}
}
}
}
reverse(nums, 0, nums.length - 1);
}
private void swap(char[] nums, int left, int right) {
char temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
private void reverse(char[] nums, int left, int right) {
while (left < right)
swap(nums, left++, right--);
}
}
No.4 有向图中最大颜色值
解题思路
先判断图中是否有环,有环直接返回 -1.
无环的话则使用动态规划求解。
代码展示
public int largestPathValue(String colors, int[][] edges) {
// 建图
int n = colors.length();
Node[] nodes = new Node[n];
for (int i = 0; i < n; i++) {
nodes[i] = new Node();
}
for (int[] e : edges) {
nodes[e[0]].nei.add(nodes[e[1]]);
}
// 判环
for (Node node : nodes) {
if (findCircle(node)) {
return -1;
}
}
// 动态规划
int best = 0;
for (int i = 'a'; i <= 'z'; i++) {
for (int j = 0; j < n; j++) {
nodes[j].dp = -1;
nodes[j].val = colors.charAt(j) == i ? 1 : 0;
}
for (int j = 0; j < n; j++) {
best = Math.max(best, dp(nodes[j]));
}
}
return best;
}
public int dp(Node cur) {
if (cur.dp == -1) {
cur.dp = 0;
for (Node node : cur.nei) {
cur.dp = Math.max(cur.dp, dp(node));
}
cur.dp += cur.val;
}
return cur.dp;
}
// 精简版的 Tarjan 算法:
// 仅用作判环,而无需求出强连通分量
// 所以并不需要真正使用栈,只需要一个标志位即可
boolean findCircle(Node cur) {
if (cur.vis) {
return cur.stk;
}
cur.vis = cur.stk = true;
for (Node node : cur.nei) {
if (findCircle(node)) {
return true;
}
}
cur.stk = false;
return false;
}
}
class Node {
int val, dp;
boolean vis, stk;
List<Node> nei;
Node() {
dp = -1;
nei = new ArrayList<>();
}
}