1658. Minimum Operations to Reduce X to Zero

1658. Minimum Operations to Reduce X to Zero

Question

You are given an integer array nums and an integer x. In one operation, you can either remove the leftmost or the rightmost element from the array nums and subtract its value from x. Note that this modifies the array for future operations.

Return *the minimum number of operations to reduce x to exactly 0 if it is possible, otherwise, return *-1.

Solution

将原有问题的从两边减去一定的值,寻找加和为x的问题转换为寻找滑动窗口中的总和为total - x的新问题。

滑动窗口

初始化当前窗口内的sum,左侧指针left与右侧指针right。
每次将一个新的元素nums[right]加入窗口范围。

当当前的sum大于寻找的target,则将nums[left]滑出窗口,更新left与sum的值。

如果当前窗口内的sum等于寻找的target,则更新记录最小操作次数的min。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public int minOperations(int[] nums, int x) {
int total = 0, min = Integer.MAX_VALUE;
for(int num : nums){
total += num;
}
int target = total - x; //将减去两侧元素并寻找和为x的结果的问题转换为用滑动窗口寻找total - x的结果。
int sum = 0, left = 0, right = 0;
while(right < nums.length){
sum += nums[right]; //调整右侧范围,加入新元素到窗口
right++;

while(left < right && sum > target){ //如果窗口内的和大于目标,则调整左侧范围
sum -= nums[left];
left++;
}
if(sum == target){ //如果窗口内的和等于目标,则更新最小操作次数
min = Math.min(min, nums.length - (right - left));
}
}
return min == Integer.MAX_VALUE ? -1 : min;
}
}
304. Range Sum Query 2D - Immutable

304. Range Sum Query 2D - Immutable

Question

Given a 2D matrix matrix, handle multiple queries of the following type:

  • Calculate the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).

Implement the NumMatrix class:

  • NumMatrix(int[][] matrix) Initializes the object with the integer matrix matrix.
  • int sumRegion(int row1, int col1, int row2, int col2) Returns the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).

Solution

前缀和/动态规划,用一个dp[][]数组记录到matrix[0][0]到matrix[i][j]区域的和。

计算两个点之间形成的总数只需用外侧的位置的前缀和加上内侧位置的前缀和,然后减去两者交换长宽位置的前缀和即可。

递推公式

计算dp[][]数组时,需要将其上侧与左侧所有数字加和,并加上matrix[][]上该位置对应的元素。
用dp[i][j-1] - dp[i-1][j-1]计算出左侧所有数字之和,dp[i-1][j]则是上侧所有数字之和。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class NumMatrix {
int[][] dp;
public NumMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
dp = new int[m+1][n+1];

for(int i = 1; i <= matrix.length; i++){
for(int j = 1; j <= matrix[0].length; j++){
dp[i][j] = dp[i][j-1] - dp[i-1][j-1] + dp[i-1][j] + matrix[i-1][j-1];
}
};
}

public int sumRegion(int row1, int col1, int row2, int col2) {
return dp[row1][col1] + dp[row2+1][col2+1] - dp[row1][col2+1] - dp[row2+1][col1];
}
}

/**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix obj = new NumMatrix(matrix);
* int param_1 = obj.sumRegion(row1,col1,row2,col2);
*/

Solution 2

暴力搜索,直接计算从row1, col1到row2, col2的元素加和。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class NumMatrix {
int[][] mat;
public NumMatrix(int[][] matrix) {
mat = matrix;
}

public int sumRegion(int row1, int col1, int row2, int col2) {
int sum = 0;
for(int i = row1; i <= row2; i++){
for(int j = col1; j <= col2; j++){
sum += mat[i][j];
}
}
return sum;
}
}

/**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix obj = new NumMatrix(matrix);
* int param_1 = obj.sumRegion(row1,col1,row2,col2);
*/
1461. Check If a String Contains All Binary Codes

1461. Check If a String Contains All Binary Codes

Question

Given a binary string s and an integer k, return true if every binary code of length k is a substring of s. Otherwise, return false.

Solution

位运算+哈希表,用整数num记录二进制编码并加入哈希表中。
首先将字符串内的前k位二进制码转换为整数。并将其数值添加到哈希表内。

滑动窗口遍历,维持num为k长度内二进制码所对应的整数,并在遍历时将num加入哈希集合。
如果哈希集合的size达到k长度对应的可组合数,则返回true,否则返回false。

位运算与掩码

为了维护整数num,首先将其二进制编码向左移动一位。
然后与mask进行按位与运算,屏蔽掉多余的位数。

mask的值为k长度对应的可组合数-1。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public boolean hasAllCodes(String s, int k) {
if(s.length() < k) return false; //字符串长度不足则返回false
char[] bin = s.toCharArray();
int n = s.length(), m = (int) Math.pow(2, k);
HashSet<Integer> set = new HashSet<>(); //哈希表记录访问过的数字

int num = Integer.parseInt(s.substring(0,k), 2); //字符串以二进制转换为整数
int mask = m-1; //掩码等于寻找长度-1
set.add(num);

for(int i = k; i < s.length(); i++){ //位运算,维护窗口内整数的值
num <<= 1; //位运算左移一位
num &= mask; //出界的位置被掩码遮盖
if(bin[i] == '1') num++;
set.add(num);
if(set.size() == m) return true; //如果哈希表长度等于2^k,则已经遍历了所有组合,返回true
}
return false;
}
}
29. Divide Two Integers

29. Divide Two Integers

Question

Given two integers dividend and divisor, divide two integers without using multiplication, division, and mod operator.

The integer division should truncate toward zero, which means losing its fractional part. For example, 8.345 would be truncated to 8, and -2.7335 would be truncated to -2.

Return *the quotient after dividing dividend by *divisor.

**Note: **Assume we are dealing with an environment that could only store integers within the 32-bit signed integer range: [−2<sup>31</sup>, 2<sup>31</sup><span> </span>− 1]. For this problem, if the quotient is strictly greater than 2<sup>31</sup><span> </span>- 1, then return 2<sup>31</sup><span> </span>- 1, and if the quotient is strictly less than -2<sup>31</sup>, then return -2<sup>31</sup>.

Solution

解题思路类似于快速幂

使用快速乘法来快速的获得商。

计算过程相当于:
60/8 = (60-32)/8 + 4 = (60-32-16)/8 + 2 + 4 = 1 + 2 + 4 = 7

需要注意的是由于只使用了整数(int)而不是长整数(long)储存数据,因此计算时需要处理各种溢出问题。

整数溢出

由于采用32位整数记录数字,负数要比正数的值范围大1。
因此当divisor为负数时,如果负数为整数最小值,则需要返回对应的整数最大值。

同时,为了在计算时防止整数溢出,因此将被除数与除数统一转为负数计算。(负数的数值比整数范围大)
当向下递归时,要保持dividend和divisor的正负性不变。

快速乘

只要被除数大于除数,则商至少为1。
循环,当被除数大于两倍的除数时,则商的结果可以直接翻倍。

否则将被除数减去当前的除数,然后向下递归新的被除数和除数。
最后返回快速乘中计算出的商加上向下递归返回的结果。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int divide(int dividend, int divisor) {
if(dividend == 0) return 0;
if(divisor == 1) return dividend;
if(divisor == -1) return dividend == Integer.MIN_VALUE ? Integer.MAX_VALUE : -dividend; //当dividend为最小整数时,其负数溢出,此时返回Integer.MAX_VALUE
int a = dividend, b = divisor;
int sign = a > 0 && b > 0 || a < 0 && b < 0 ? 1 : -1; //记录除数与被除数是否同号
if(dividend > 0) a = -a; //将除数与被除数转换为负数,因为负数能记录的数值比正数大1,防止溢出
if(divisor > 0) b = -b;
if(a > b) return 0; //被除数小于除数时返回0
int res = 1;
while(a <= b+b && b+b < 0){ //算法核心,快速乘法
b += b; //除数每次翻倍,直到大于被除数
res += res; //商的结果翻倍
}
res = sign == 1 ? res : -res; //根据是否同号记录商

divisor = dividend > 0 ? -divisor : divisor; //当原有被除数是正数时,要将除数取反
return res + divide(a-b, divisor);
}
}
318. Maximum Product of Word Lengths

318. Maximum Product of Word Lengths

Question

Given a string array words, return the maximum value of length(word[i]) * length(word[j]) where the two words do not share common letters. If no such two words exist, return 0.

Solution

正常的思路可能是用哈希表保存字符串中出现过的字符。此时表的大小是26也是一个常数。

我们可以采用位运算进行状态压缩,通过一个整数的二进制位保存二十六个字符的存在状态。

状态压缩

我们采用一个整数数组bin[]储存状态压缩后的整数。

遍历每个字符串,在字符串中遍历每一个字符。
初始化整数bit为0。在遍历字符时计算当前字符与字符’a’距离的差n,然后将1左移n位,填入(或运算)整数bit中。

比较

遍历words[]中的两个字符串,当bin[i]与bin[j]进行与运算结果为0时,则两个字符串没有共同字符。
此时更新二者长度乘积的最大值max。

最后返回max即可。

时间复杂度:O(L + n2)。L为所有字符的总长度。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public int maxProduct(String[] words) {

int max = 0;
int bin[] = new int[words.length];

for(int i = 0; i < words.length; i++){
int bit = 0;
for(int j = 0; j < words[i].length(); j++){
bit |= (1 << (words[i].charAt(j) - 'a'));
}
bin[i] = bit;
}

for(int i = 0; i < words.length; i++){
for(int j = i+1; j < words.length; j++){
if((bin[i] & bin[j]) == 0) max = Math.max(max, words[i].length() * words[j].length());
}
}
return max;
}
}
474. Ones and Zeroes

474. Ones and Zeroes

Question

You are given an array of binary strings strs and two integers m and n.

Return the size of the largest subset of strs such that there are at most m 0‘s and n 1‘s in the subset.

A set x is a subset of a set y if all elements of x are also elements of y.

Solution 1

0-1背包问题的升级版。经典的背包问题只有一种容量,而这个问题实际等于有两种容量。

经典背包问题需要用二维数组动态规划,分别为物品和容量。
而这道题需要用三维数组动态规划,分别为字符串,0的容量和1的容量。

我们采用一个三维数组dp[i][j][k]保存可取最多物品的数量
对于每个物品i,我们都可以取(数量+1)或不取(保持上一个物品的状态)。
j和k相当于分别记录了取“0”的总数和“1”的总数

遍历三个维度,并计算字符串中0和1的个数。

  • 如果当总容量大于当前物品中zeros和ones的数量,则可以取当前的物品

    • 如果取当前的物品,则dp[]数组的总数等于上一个物品的状态加一,即dp[i-1][j-zeros][k-ones]。
    • 也可以不取当前的物品,则dp[]数组的总数直接保持上一个物品的状态
  • 如果当前背包总容量小于zeros和ones的数量,则不能取当前物品。

    • 数组dp[]保持上一个物品的状态

时间复杂度:O(lmn + L),L是数组中所有字符串长度之和。
空间复杂度:O(lmn)。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][][] dp = new int[strs.length+1][m+1][n+1];

for(int i = 1; i <= strs.length; i++){
int zeros = 0, ones = 0;
for(char c : strs[i-1].toCharArray()){
if(c == '0') zeros++;
else ones++;
}

for(int j = 0; j <= m; j++){
for(int k = 0; k <= n; k++){
if(j - zeros >= 0 && k - ones >=0) dp[i][j][k] = Math.max(dp[i-1][j][k], dp[i-1][j-zeros][k-ones] + 1);
else dp[i][j][k] = dp[i-1][j][k];
}
}
}
return dp[strs.length][m][n];
}
}

Solution 2

由于dp[i][][]的上一个状态只涉及到dp[i-1][][],因此我们可以采用滚动数组,去掉数组的一个维度,压缩空间。
此时需要从m到zeros,从n到ones倒序遍历,保证dp[i][][]转移过来的是dp[i-1][][]的元素。

此时的空间复杂度降低为O(mn)。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m+1][n+1];

for(String s : strs){ //记录每个位置对应的0和1数量
int zeros = 0, ones = 0;
for(char c : s.toCharArray()){
if(c == '0') zeros++;
else ones++;
}

for(int i = m; i >= zeros; i--){
for(int j = n; j >= ones; j--){
dp[i][j] = Math.max(dp[i][j], dp[i-zeros][j-ones] + 1);
}
}
}
return dp[m][n];
}
}

Solution 3

递归+记忆化搜索,保存并返回每个位置的最大长度。
如果位置越界则返回0。
如果memo[i][zero][one]不为0,则返回memo[i][zero][one]。

如果当前字符串的“0”和“1”的个数大于剩余的“0”和“1”的个数,则可以取当前字符串,递归下一个位置并加一。
也可以不取当前的字符串,递归下一个位置。当前位置memo[i][zero][one]等于两者中的最大值。

否则无法取当前字符串,直接递归下一个位置。当前位置等于0。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
String[] s;
int[] zeros, ones;
int[][][] memo;
public int findMaxForm(String[] strs, int m, int n) {
s = strs;
zeros = new int[strs.length];
ones = new int[strs.length];
memo = new int[strs.length][m+1][n+1];

for(int i = 0; i < strs.length; i++){ //记录每个位置对应的0和1数量
for(int j = 0; j < strs[i].length(); j++){
if(s[i].charAt(j) == '0') zeros[i]++;
else ones[i]++;
}
}
return dfs(0, m, n);
}

private int dfs(int i, int zero, int one){
if(i >= s.length){
return 0;
}
if(memo[i][zero][one] != 0) return memo[i][zero][one];

int maxPossibleSubset = 0;

if(zero-zeros[i] >= 0 && one-ones[i] >= 0){
maxPossibleSubset = 1 + dfs(i+1, zero-zeros[i], one-ones[i]);
}
memo[i][zero][one] = Math.max(maxPossibleSubset, dfs(i+1, zero, one));
return memo[i][zero][one];

}
}

2280. Minimum Lines to Represent a Line Chart

Question

You are given a 2D integer array stockPrices where stockPrices[i] = [day<sub>i</sub>, price<sub>i</sub>] indicates the price of the stock on day day<sub>i</sub> is price<sub>i</sub>. A line chart is created from the array by plotting the points on an XY plane with the X-axis representing the day and the Y-axis representing the price and connecting adjacent points. One such example is shown below:

Solution

如果只有一个点,无法组成线段则返回0。否则至少可以组成1条线段。

首先将所有点根据x的位置排序,然后一次比较连续的各个向量的方向。
为了防止除法精度问题,计算两个向量(三个点组成两个向量)的叉乘,如果叉乘为0,则说明两个向量是平行的,此时不需要增加计数。
如果叉乘结果不等于0,则将计数+1。

最后返回计数的结果。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int minimumLines(int[][] stockPrices) {
if(stockPrices.length == 1) return 0;

Arrays.sort(stockPrices, (a,b) -> a[0] - b[0]);
int count = 1, lastX = 0, lastY = 0;

for(int i = 1; i < stockPrices.length; i++){
int x = stockPrices[i][0] - stockPrices[i-1][0];
int y = stockPrices[i][1] - stockPrices[i-1][1];

int k = lastX * y - lastY * x;
if(k != 0) count++;
lastX = x;
lastY = y;
}
return count;
}
}

2279. Maximum Bags With Full Capacity of Rocks

Question

You have n bags numbered from 0 to n - 1. You are given two 0-indexed integer arrays capacity and rocks. The i<sup>th</sup> bag can hold a maximum of capacity[i] rocks and currently contains rocks[i] rocks. You are also given an integer additionalRocks, the number of additional rocks you can place in any of the bags.

Return* the maximum number of bags that could have full capacity after placing the additional rocks in some bags.*

Solution

计算每个背包的剩余空间,然后进行排序。
按从小到大的顺序依次减少石头的总数。
设置i作为选取石头的计数。每次循环将i增加,直到剩余的石头数量小于0。
如果最后剩下的石头仍然大于等于0,则返回计数。
否则返回计数-1。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public int maximumBags(int[] capacity, int[] rocks, int additionalRocks) {
int[] diff = new int[capacity.length];
for(int i = 0 ; i < capacity.length; i++){
diff[i] = capacity[i] - rocks[i];
}

Arrays.sort(diff);
int i = 0;
while(additionalRocks > 0 && i < diff.length){
additionalRocks -= diff[i];
i++;
}
return additionalRocks >= 0 ? i : i - 1;
}
}
647. Palindromic Substrings

647. Palindromic Substrings

Question

Given a string s, return the number of palindromic substrings in it.

A string is a palindrome when it reads the same backward as forward.

A substring is a contiguous sequence of characters within the string.

Solution

Manacher算法,与5. Longest Palindromic Substring的实现方法相同。

首先处理字符串。
然后采用中心拓展计算各个位置的拓展长度,并维护c与r。
每次遍历时计算结果,将当前可扩展长度加一然后除以二后加入结果。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Solution {
int n;
int[] p;
String newString;
public int countSubstrings(String s) {
n = s.length();
StringBuffer sb = new StringBuffer();
if(n == 0) { //对字符串进行处理
sb.append("^$");
}
else{
sb.append("^");
for(int i = 0; i < s.length(); i++){
sb.append('#');
sb.append(s.charAt(i));
}
sb.append("#$");
}
p = new int[sb.length()];
newString = sb.toString();

return manacher();
}

private int manacher(){
int res = 0, c = 0, r = 0;
for(int i = 1; i < newString.length()-1; i++){
int m = 2 * c - i;
if(i < r) p[i] = Math.min(r-i, p[m]);

while(newString.charAt(i+p[i]+1) == newString.charAt(i-p[i]-1)){ //中心拓展
p[i]++;
}

if(i+p[i] > r){ //更新c与r
c = i;
r = i + p[i];
}
res += (p[i]+1)/2; //向上取整
}
return res;
}
}

Solution 2

中心拓展,辅助方法count()用来计算每个字符可以组成的最大回文数。

注意每次需要计算奇数长度回文和偶数长度回文两种情况。
遍历所有字符并加和,返回总数。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
String word;
public int countSubstrings(String s) {
word = s;
int ret = 0;
for(int i = 0; i < s.length(); i++){
ret+=count(i);
}
return ret;
}

private int count(int i){
int count = 1, left = i-1, right = i+1;

while(left >= 0 && right < word.length() && word.charAt(left) == word.charAt(right)){
count++;
left--;
right++;
}

left = i;
right = i+1;

while(left >= 0 && right < word.length() && word.charAt(left) == word.charAt(right)){
count++;
left--;
right++;
}
return count;
}
}
63. Unique Paths II

63. Unique Paths II

Question

You are given an m x n integer array grid. There is a robot initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m-1][n-1]). The robot can only move either down or right at any point in time.

An obstacle and space are marked as 1 or 0 respectively in grid. A path that the robot takes cannot include any square that is an obstacle.

Return the number of possible unique paths that the robot can take to reach the bottom-right corner.

The testcases are generated so that the answer will be less than or equal to 2 * 10<sup>9</sup>.

Solution

机器人只朝向一个方向移动,不存在折返。
因此可以采用动态规划,直接记录到某个点的总路线数。
当遇到障碍时(即当前访问的格子为1)则不更新dp[]数组。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {

int m = obstacleGrid.length;
int n = obstacleGrid[0].length;

int[][] dp = new int[m+1][n+1];
dp[0][1] = 1;

for(int x = 1; x < m+1; x++){
for(int y = 1; y < n+1; y++){
if(obstacleGrid[x-1][y-1] == 0){
dp[x][y] = dp[x][y-1] + dp[x-1][y];
}
}
}
return dp[m][n];
}
}
1379. Find a Node of a Binary Tree in a Clone Tree

1379. Find a Node of a Binary Tree in a Clone Tree

Question

Given two binary trees original and cloned and given a reference to a node target in the original tree.

The cloned tree is a copy of the original tree.

Return a reference to the same node in the cloned tree.

Note that you are not allowed to change any of the two trees or the target node and the answer must be a reference to a node in the cloned tree.

Solution

DFS搜索,同步递归original和cloned的子节点。
当在original里找到target的时候返回当前的cloned节点。

注意可以先判断一个分支中的返回值是否为空,如果不为空则直接返回。反之则返回另一个分支。这样操作可以进行一部分剪枝。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/

class Solution {
public final TreeNode getTargetCopy(final TreeNode original, final TreeNode cloned, final TreeNode target) {
if(original == null) return null;
if(original.equals(target)) return cloned;

TreeNode left = getTargetCopy(original.left, cloned.left, target);
if(left != null) return left;
else return getTargetCopy(original.right, cloned.right, target);
}
}

2275. Largest Combination With Bitwise AND

Problem

The bitwise AND of an array nums is the bitwise AND of all integers in nums.

  • For example, for nums = [1, 5, 3], the bitwise AND is equal to 1 & 5 & 3 = 1.

  • Also, for nums = [7], the bitwise AND is 7.

You are given an array of positive integers candidates. Evaluate the bitwise AND of every combination of numbers of candidates. Each number in candidates may only be used once in each combination.

Return *the size of the largest combination of candidates with a bitwise AND greater than *0.

Solution

相当于将各个数字进行掩码操作,计算各个数组的同一个位上1的数量即可。

bin[]数组记录各个数字的各个位上的1的数量。
如果当前数字与1进行掩码操作后等于1,则将该位数量加一。
然后将当前数字向右移动一位,直至将所有的位都统计完。

最后返回各个位上的最大值即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public int largestCombination(int[] candidates) {
int[] bin = new int[31];
int res = 0;
for(int candidate : candidates){
int count = 0;
while(count < 31){
if((candidate & 1) == 1){
bin[count]++;
}
candidate = candidate >> 1;
count++;
}
}
for(int time : bin){
res = Math.max(res, time);
}
return res;
}
}

2274. Maximum Floors Without Special Floors

Question

Alice manages a company and has rented some floors of a building as office space. Alice has decided some of these floors should be special floors, used for relaxation only.

You are given two integers bottom and top, which denote that Alice has rented all the floors from bottom to top (inclusive). You are also given the integer array special, where special[i] denotes a special floor that Alice has designated for relaxation.

Return the maximum number of consecutive floors without a special floor.

Solution

可以视为特殊的动态规划。

计算每个特殊房间与上一个特殊房间的层数。(可以将底层的上一个房间视为特殊房间,需要将第一个房间设置为bottom-1)。
当距离大于当前结果时则更新res。

最后需要计算最后一层到上一个特殊房间的距离。(可以将顶楼的上一层视为特殊房间,因此直接计算top - lastRoom的层数即可)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int maxConsecutive(int bottom, int top, int[] special) {
int res = 0;
int lastRoom = bottom-1;
Arrays.sort(special);

for(int room : special){
int temp = room - lastRoom - 1;
res = Math.max(res, temp);
lastRoom = room;

}
int temp = top - lastRoom;
res = Math.max(res, temp);

return res;
}
}
1302. Deepest Leaves Sum

1302. Deepest Leaves Sum

Question

Given the root of a binary tree, return the sum of values of its deepest leaves.

Solution

BFS搜索,层序遍历,每次计算每个层级的总和。
最后返回最后一个层级总和。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int deepestLeavesSum(TreeNode root) {
Deque<TreeNode> q = new LinkedList<>();
int res = 0;

q.offer(root);

int level = q.size();

while(!q.isEmpty()){
int sum = 0;
for(int i = 0; i < level; i++){
TreeNode curr = q.poll();
sum += curr.val;
if(curr.left != null) q.offer(curr.left);
if(curr.right != null) q.offer(curr.right);
}
res = sum;
level = q.size();
}
return res;
}
}
743. Network Delay Time

743. Network Delay Time

Question

You are given a network of n nodes, labeled from 1 to n. You are also given times, a list of travel times as directed edges times[i] = (u<sub>i</sub>, v<sub>i</sub>, w<sub>i</sub>), where u<sub>i</sub> is the source node, v<sub>i</sub> is the target node, and w<sub>i</sub> is the time it takes for a signal to travel from source to target.

We will send a signal from a given node k. Return the time it takes for all the n nodes to receive the signal. If it is impossible for all the n nodes to receive the signal, return -1.

Solution

Dijkstra算法

此题可以转化为求起始节点到最远距离的节点的距离。单源最短路径问题,可以采用Dijkstra算法。

采用一个visited[]数组记录初始节点的访问状况。
同时dist[]数组记录到达这一节点的最小距离,初始化为无限大。

进行BFS搜索,每次优先访问当前节点的子节点的最近子节点,并更新子节点与初始节点距离。
最后遍历dist[]数组,如果有元素仍为无限大,则BFS搜索未遍历到,返回-1。
否则返回数组内最大的距离即可。

建立映射

首先通过哈希表,将起始节点与有向边建立起映射关系。列表中储存子节点和对应边上的权值。
注意由于index是-1的,因此在组成列表时需要将当前数字减一。

优先级队列

采用优先级队列组成小根堆,每次将当前的最小距离作为权值加入队列。
初始化队列时需要将起始节点(k-1)放入,此时的总距离为0。

当当前的子节点的cost加上起始节点的距离小于子节点的最小距离时,更新子节点最小距离。
同时将子节点当前最小距离作为比较对象传入优先级队列。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
HashMap<Integer, List<int[]>> edges = new HashMap<>();

for(int[] time : times){ //建立有向边
int source = time[0] - 1, kid = time[1] - 1, cost = time[2]; //注意index需要-1
List<int[]> list = edges.getOrDefault(source, new ArrayList<>());
list.add(new int[]{kid, cost}); //建立起点——终点映射
edges.put(source, list);
}

int[] visited = new int[n];
int[] dist = new int[n];
Arrays.fill(dist, Integer.MAX_VALUE);

PriorityQueue<int[]> pq = new PriorityQueue<>((a,b) -> a[1] - b[1]); //优先级队列,最小堆每次访问距离最近的节点

int start = k-1;
dist[start] = 0;
pq.offer(new int[]{start, 0}); //start为初始节点,后面的距离为了实现优先级队列

while(!pq.isEmpty()){
int[] curr = pq.poll();
int source = curr[0];

if(visited[source] == 1) continue;
visited[source] = 1;

List<int[]> children = edges.getOrDefault(source, new ArrayList<>()); //获取当前起点的所有边
for(int[] child : children){
int kid = child[0], cost = child[1];

if(cost + dist[source] < dist[kid]){ //如果新的距离小于之前的最小距离,则更新距离并将新的起点加入优先级队列
dist[kid] = cost + dist[source];
pq.offer(new int[]{kid, dist[kid]}); //更新的距离是从出发节点到当前节点的距离,每次优先访问最近的节点
}
}
}

int res = 0;

for(int d : dist){ //最后遍历,距离的最大值就是结果
res = Math.max(res, d);
}
return res == Integer.MAX_VALUE ? -1 : res;
}
}