1491-Average-Salary-Excluding-the-Minimum-and-Maximum-Salary
1579. Remove Max Number of Edges to Keep Graph Fully Traversable

1579. Remove Max Number of Edges to Keep Graph Fully Traversable

Question

Alice and Bob have an undirected graph of n nodes and three types of edges:

  • Type 1: Can be traversed by Alice only.
  • Type 2: Can be traversed by Bob only.
  • Type 3: Can be traversed by both Alice and Bob.

Given an array edges where edges[i] = [typei, ui, vi] represents a bidirectional edge of type typei between nodes ui and vi, find the maximum number of edges you can remove so that after removing the edges, the graph can still be fully traversed by both Alice and Bob. The graph is fully traversed by Alice and Bob if starting from any node, they can reach all other nodes.

Return the maximum number of edges you can remove, or return -1 if Alice and Bob cannot fully traverse the graph.

Solution

对于A,B皆互通的边的权重比只对A或B连通的边的权重高。(多提供另一种联通)

因此先选择双连通的边,并加入两个并查集,由于选择了边,因此res–。

然后选择单连通的边,如果并查集中的两个节点并不互通,则选择这个边,并加入对应并查集。

每次连通两个节点,则集合数量减少1。

如果最终两个并查集的数量不是1,则并非所有节点都互相连通,返回-1。

否则返回未选择的边数res。

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class Solution {
public int maxNumEdgesToRemove(int n, int[][] edges) {
UnionFind ufA = new UnionFind(n), ufB = new UnionFind(n);
int res = edges.length;

for(int[] edge : edges){
int type = edge[0], u = edge[1] - 1, v = edge[2] - 1;
if(type == 3 && !ufA.isConnected(u, v)){
ufA.union(u, v);
ufB.union(u, v);
res--;
}

}

for(int[] edge : edges){
int type = edge[0], u = edge[1] - 1, v = edge[2] - 1;

if(type == 1 && !ufA.isConnected(u, v)){
ufA.union(u, v);
res--;
}
else if(type == 2 && !ufB.isConnected(u, v)){
ufB.union(u, v);
res--;
}
}
return ufA.sets == ufB.sets && ufA.sets == 1 ? res : -1;
}
}

class UnionFind{
int[] parent;
int[] rank;
public int sets;

UnionFind(int n){
parent = new int[n];
rank = new int[n];
sets = n;
for(int i = 0; i < n; i++){
parent[i] = i;
rank[i] = 0;
}
}

public int find(int i){
if(parent[i] == i){
return i;
}
return find(parent[i]);
}

public void union(int a, int b){
int pa = find(a), pb = find(b);
if(pa != pb) sets--;
if(rank[pa] < rank[pb]){
parent[pa] = pb;
}
else if(rank[pa] > rank[pb]){
parent[pb] = pa;
}
else{
parent[pa] = pb;
rank[pb]++;
}
}

public boolean isConnected(int a, int b){
return find(a) == find(b);
}
}
1697. Checking Existence of Edge Length Limited Paths

1697. Checking Existence of Edge Length Limited Paths

Question

An undirected graph of n nodes is defined by edgeList, where edgeList[i] = [ui, vi, disi] denotes an edge between nodes ui and vi with distance disi. Note that there may be multiple edges between two nodes.

Given an array queries, where queries[j] = [pj, qj, limitj], your task is to determine for each queries[j] whether there is a path between pj and qj such that each edge on the path has a distance strictly less than limitj .

Return a boolean array answer, where answer.length == queries.length and the jth value of answer is true if there is a path for queries[j] is true, and false otherwise.

Read more
319. Bulb Switcher

319. Bulb Switcher

Question

There are n bulbs that are initially off. You first turn on all the bulbs, then you turn off every second bulb.

On the third round, you toggle every third bulb (turning on if it’s off or turning off if it’s on). For the ith round, you toggle every i bulb. For the nth round, you only toggle the last bulb.

Return the number of bulbs that are on after n rounds.

Solution

Each position is only switched on its factor rounds, and factors appear in pairs except when squared, where the factor is the same. Therefore, the problem is equivalent to finding the number of times a perfect square appears.

每个位置只在其因子回合会被切换,除了平方时因子相同,其他时候因子都是成对出现的。因此改题目等价于求平方数出现次数。

Code

1
2
3
4
5
6
7
8
9
10
class Solution {
public:
int bulbSwitch(int n) {
// bulbs will switch in factor round
// since factor round will appear with pair
// we just need to count square round

return (int) sqrt(n);
}
};
26. Remove Duplicates from Sorted Array

26. Remove Duplicates from Sorted Array

Question

Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same.

Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements.

Return k* after placing the final result in the first k slots of *nums.

Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory.

Solution

由于数组本身已经排序,只要比较当前nums中的元素是否大于上一个保存的数值就可以决定是否保留。
创建一个k记录遍历的位置,每次比较nums[k]与nums[i]的位置元素的大小,如果当前的nums[i]大于nums[k],则将k位置向后移动1,并将下一个位置记录为nums[i]。

最后返回k+1。

Code

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int removeDuplicates(int[] nums) {
int k = 0;
for(int i = 0; i < nums.length; i++){
if(nums[k] < nums[i]){
k++;
nums[k] = nums[i];
}
}
return k + 1;
}
}
1578. Minimum Time to Make Rope Colorful

1578. Minimum Time to Make Rope Colorful

Problem

Alice has n balloons arranged on a rope. You are given a 0-indexed string colors where colors[i] is the color of the i<sup>th</sup> balloon.

Alice wants the rope to be colorful. She does not want two consecutive balloons to be of the same color, so she asks Bob for help. Bob can remove some balloons from the rope to make it colorful. You are given a 0-indexed integer array neededTime where neededTime[i] is the time (in seconds) that Bob needs to remove the i<sup>th</sup> balloon from the rope.

Return the minimum time Bob needs to make the rope colorful.

Solution

滑动窗口,遍历字符串。
common用来记录连续颜色相同的个数,初始化为1。
如果当前字符与下一个字符相同,则窗口向右侧扩展,common++。
遍历时记录替换气球需要的最大时间maxTime和替换掉所有同色气球的总时间deleteTime。

如果common大于1,则总时间加上需要删除的时间(刨除最大时间maxTime)。
更新i为i + common。

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 minCost(String colors, int[] neededTime) {
int i = 0, totalTime = 0;
char[] c = colors.toCharArray();
while(i < neededTime.length){
int common = 1, maxTime = neededTime[i], deleteTime = neededTime[i];
while(i + common < neededTime.length && c[i] == c[i + common]){
maxTime = Math.max(maxTime, neededTime[i + common]);
deleteTime += neededTime[i + common];
common++;
}
if(common > 1){
deleteTime -= maxTime;
totalTime += deleteTime;
}
i += common;
}
return totalTime;
}
}

609. Find Duplicate File in System

Question

Given a list paths of directory info, including the directory path, and all the files with contents in this directory, return all the duplicate files in the file system in terms of their paths. You may return the answer in any order.

A group of duplicate files consists of at least two files that have the same content.

A single directory info string in the input list has the following format:

  • "root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ... fn.txt(fn_content)"

It means there are n files (f1.txt, f2.txt ... fn.txt) with content (f1_content, f2_content ... fn_content) respectively in the directory “root/d1/d2/.../dm". Note that n >= 1 and m >= 0. If m = 0, it means the directory is just the root directory.

The output is a list of groups of duplicate file paths. For each group, it contains all the file paths of the files that have the same content. A file path is a string that has the following format:

  • "directory_path/file_name.txt"

Solution

使用StringBuffer对字符串进行处理。
采用HashMap建立内容和对应列表的映射。

遍历处理字符串,并添加到map中。
最后遍历map,如果对应的列表size大于1,则加入结果。

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
class Solution {
public List<List<String>> findDuplicate(String[] paths) {
List<List<String>> res = new ArrayList<>();
HashMap<String, List<String>> map = new HashMap<>();

for(String path : paths){
StringBuffer folder = new StringBuffer();

int i = 0;
while(path.charAt(i) != ' '){
folder.append(path.charAt(i));
i++;
}
while(i < path.length()){
while(path.charAt(i) == ' ') i++;
StringBuffer filename = new StringBuffer();
while(i < path.length() && path.charAt(i) != '('){
filename.append(path.charAt(i));
i++;
}

StringBuffer content = new StringBuffer();
while(i < path.length() && path.charAt(i) != ')'){
content.append(path.charAt(i));
i++;
}
i++;
List<String> arr = map.getOrDefault(content.toString(), new ArrayList<String>());
arr.add(folder.toString() + '/' + filename);
map.put(content.toString(), arr);
}
}

for(String content : map.keySet()){
if(map.get(content).size() > 1) res.add(map.get(content));
}

return res;
}
}
42. Trapping Rain Water

42. Trapping Rain Water

Question

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

Solution

双指针,设置当前左侧的最大高度left和右侧的最大高度right。

分别从两侧遍历height[]数组,当出现更高的height时更新left和right。
否则记录left和right与height[i]的差值,并记录在数组waterLeft[]和waterRight[]中。

遍历两个数组,添加两者中的最小值到volume。

*由于单个参数只记录了一侧的最大值,因此最大值另一侧的水的体积会被多计算,因此分别从两侧遍历来获得最小值。

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 trap(int[] height) {
int n = height.length, left = 0, right = 0, volume = 0;
int[] waterLeft = new int[n], waterRight = new int[n];

for(int i = 0; i < n; i++){
if(left <= height[i]) left = height[i];
else waterLeft[i] = left - height[i];
}

for(int i = n - 1; i >= 0; i--){
if(right <= height[i]) right = height[i];
else waterRight[i] = right - height[i];
}

for(int i = 0; i < n; i++){
volume += Math.min(waterLeft[i], waterRight[i]);
}

return volume;
}
}
1770. Max Score from Multiplication Operations

1770. Max Score from Multiplication Operations

Question

You are given two integer arrays nums and multipliers** **of size n and m respectively, where n >= m. The arrays are 1-indexed.

You begin with a score of 0. You want to perform exactly m operations. On the i<sup>th</sup> operation (1-indexed), you will:

  • Choose one integer x from **either the start or the end **of the array nums.
  • Add multipliers[i] * x to your score.
  • Remove x from the array nums.

Return *the maximum score after performing *m operations.

Solution

动态规划,dp[][]数组记录左边取的个数和右边取的个数。

从取1开始到取multipliers的长度位置开始遍历。
然后从left取0个开始,直到left取i个为止遍历。
计算对应的right指针位置。

注意访问数组时需要访问left和right的上一个位置。

如果left为0,则只能取右侧的上一个位置加上右侧的上一个数值乘以mul。
如果right为0,则只能取左侧的上一个位置加上左侧的上一个数值乘以mul。
否则取两者之间的最大值。

最后遍历数组中left + right和为m的位置,并返回最大值。

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 maximumScore(int[] nums, int[] multipliers) {
int n = nums.length, m = multipliers.length;
int[][] dp = new int[m+1][m+1];

for(int i = 1; i <= m; i++){
int mul = multipliers[i-1];
for(int l = 0; l <= i; l++){
int r = i - l;
int iL = l - 1, iR = n - r;
if(l == 0) dp[l][r] = dp[l][r-1] + mul * nums[iR];
else if(r == 0) dp[l][r] = dp[l-1][r] + mul * nums[iL];
else dp[l][r] = Math.max(dp[l-1][r] + mul * nums[iL], dp[l][r-1] + mul * nums[iR]);
}
}
int ans = Integer.MIN_VALUE;
for(int l = 1; l <= m; l++){
int r = m - l;
ans = Math.max(ans, dp[l][r]);
}
return ans;
}
}
1457. Pseudo-Palindromic Paths in a Binary Tree

1457. Pseudo-Palindromic Paths in a Binary Tree

Question

Given a binary tree where node values are digits from 1 to 9. A path in the binary tree is said to be pseudo-palindromic if at least one permutation of the node values in the path is a palindrome.

Return the number of pseudo-palindromic paths going from the root node to leaf nodes.

Solution

用数组bin[]记录一个树枝上的节点。

回溯,遇到根节点则判断数组bin[]中是否只有0个或1个奇数的数字。

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
/**
* 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 {
int res;
int[] bin;
public int pseudoPalindromicPaths (TreeNode root) {
res = 0;
bin = new int[10];
backtrack(root);
return res;
}

private void backtrack(TreeNode root){
if(root.left == null && root.right == null){
bin[root.val]++;
boolean flag = false;
for(int i = 0; i < bin.length; i++){
if(flag && (bin[i] & 1) == 1){
bin[root.val]--;
return;
}
else if((bin[i] & 1) == 1) flag = true;
}
res++;
bin[root.val]--;
return;
}
bin[root.val]++;
if(root.left != null) backtrack(root.left);
if(root.right != null) backtrack(root.right);
bin[root.val]--;
}
}
393. UTF-8 Validation

393. UTF-8 Validation

Question

Given an integer array data representing the data, return whether it is a valid UTF-8 encoding (i.e. it translates to a sequence of valid UTF-8 encoded characters).

A character in UTF8 can be from 1 to 4 bytes long, subjected to the following rules:

  1. For a 1-byte character, the first bit is a 0, followed by its Unicode code.
  2. For an n-bytes character, the first n bits are all one’s, the n + 1 bit is 0, followed by n - 1 bytes with the most significant 2 bits being 10.

x denotes a bit in the binary form of a byte that may be either 0 or 1.

**Note: **The input is an array of integers. Only the least significant 8 bits of each integer is used to store the data. This means each integer represents only 1 byte of data.

Solution

位运算,循环更新UTF头部的位置start。
getByte()方法用来计算位数。
check()方法用来检查从start+1开始直到位数结束是否二进制位数以10开头。
isStartWith10()方法使用掩码判断二进制是否以10开头。

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
class Solution {
int[] dt;
final int MASK = 0b11000000;
public boolean validUtf8(int[] data) {
dt = data;
int start = 0;

while(start < data.length){
int bit = getByte(start);
if(bit == -1 || start + bit > data.length) return false;
if(!check(start, bit)) return false;
start += bit;
}
return true;
}

private int getByte(int start){
int bit = 5;
for(int i = 0; i < 8; i++){
if((dt[start] & 1) == 0) bit = 7 - i;
dt[start] >>= 1;
}
if(bit == 0) return 1;
else if(bit == 1 || bit > 4) return -1;
else return bit;
}

private boolean check(int start, int bit){
for(int i = start + 1; i < start + bit; i++) if(!isStartWith10(dt[i])) return false;
return true;
}

private boolean isStartWith10(int num){
return (num & MASK) == 0b10000000;
}
}
1383. Maximum Performance of a Team

1383. Maximum Performance of a Team

Question

You are given two integers n and k and two integer arrays speed and efficiency both of length n. There are n engineers numbered from 1 to n. speed[i] and efficiency[i] represent the speed and efficiency of the i<sup>th</sup> engineer respectively.

Choose at most k different engineers out of the n engineers to form a team with the maximum performance.

The performance of a team is the sum of their engineers’ speeds multiplied by the minimum efficiency among their engineers.

Return the maximum performance of this team. Since the answer can be a huge number, return it modulo 10<sup>9</sup><span> </span>+ 7.

Solution

排序,将所有工程师根据其效率降序排列。

此时遍历时后一个工程师的效率一定小于等于前一个工程师。

因此,此时遍历到每一个工程师,其前面所有的工程师的efficiency均大于等于其本身。
维护一个所有选取工程师的总速度ttSpd,每次计算并更新max的值。
用最小堆来维护选取的工程师速度,如果优先级队列的尺寸超过k-1,则poll掉队列内最低的速度。

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 {
public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
final int mod = (int) Math.pow(10, 9) + 7;
int[][] engineer = new int[n][2];

for(int i = 0; i < n; i++){
engineer[i][0] = speed[i];
engineer[i][1] = efficiency[i];
}

Arrays.sort(engineer, new Comparator<int[]>(){
public int compare(int[] a, int[] b){
return b[1] - a[1];
}
});

long max = 0, ttSpd = 0;

PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int i = 0; i < n; i++){
int s = engineer[i][0], e = engineer[i][1];
ttSpd += s;
max = Math.max(max, ttSpd * e);
pq.add(s);
if(pq.size() == k) ttSpd -= pq.poll();
}

return (int) (max % mod);
}
}

1996. The Number of Weak Characters in the Game

1996. The Number of Weak Characters in the Game

Question

You are playing a game that contains multiple characters, and each of the characters has two main properties: attack and defense. You are given a 2D integer array properties where properties[i] = [attack<sub>i</sub>, defense<sub>i</sub>] represents the properties of the i<sup>th</sup> character in the game.

A character is said to be weak if any other character has both attack and defense levels strictly greater than this character’s attack and defense levels. More formally, a character i is said to be weak if there exists another character j where attack<sub>j</sub><span> </span>> attack<sub>i</sub> and defense<sub>j</sub><span> </span>> defense<sub>i</sub>.

Return the number of weak characters.

Solution

本题与354. Russian Doll Envelopes相近。

首先对数组进行排序,根据角色的attack数值降序排序,如果两者的attack数值相等,则根据两者的defence升序排序。

记录一个遍历过的最大defence数值maxDefence,遍历数组,如果当前maxDef大于角色的防御值,则此时当前遍历角色的attack与defence均严格小于上一个计算的角色,因此count加一。
否则更新maxDef。

*由于attack是降序的,因此可以确定遍历时下一组数组的attack一定更弱。(由于相同attack的角色是根据defence升序排列,因此记录maxDef时会逐个更新maxDef的值。)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int numberOfWeakCharacters(int[][] properties) {
int count = 0, maxDef = Integer.MIN_VALUE;

Arrays.sort(properties, new Comparator<int[]>(){
public int compare(int[] a, int[] b){
if(a[0] == b[0]) return a[1] - b[1];
return b[0] - a[0];
}
});

for(int[] character : properties){
if(maxDef > character[1]) count++;
else maxDef = character[1];
}
return count;
}
}
606. Construct String from Binary Tree

606. Construct String from Binary Tree

Question

Given the root of a binary tree, construct a string consisting of parenthesis and integers from a binary tree with the preorder traversal way, and return it.

Omit all the empty parenthesis pairs that do not affect the one-to-one mapping relationship between the string and the original binary tree.

Solution

DFS搜索,先序遍历到每个节点将其加入StringBuffer。
如果当前节点有左子节点或右子节点,则递归左子节点,并在前后添加一对括号。(如果有右子节点的情况即使左子节点为空也需要添加一对括号加以区别。)
如果当前节点有右子节点,则递归右子节点,并在前后添加一对括号。

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 {
StringBuffer sb;
public String tree2str(TreeNode root) {
sb = new StringBuffer();
dfs(root);
return sb.toString();
}

private void dfs(TreeNode root){
if(root == null) return;
sb.append(root.val);

boolean hasLeft = root.left != null, hasRight = root.right != null;

if(hasLeft || hasRight) sb.append("(");
dfs(root.left);
if(hasLeft || hasRight) sb.append(")");

if(hasRight) sb.append("(");
dfs(root.right);
if(hasRight) sb.append(")");
}
}
814. Binary Tree Pruning

814. Binary Tree Pruning

Question

Given the root of a binary tree, return the same tree where every subtree (of the given tree) not containing a 1 has been removed.

A subtree of a node node is node plus every node that is a descendant of node.

Solution 1

DFS搜索,首先递归两个子节点。
在搜索时如果节点为0且两个子节点均为null,则返回null。否则返回节点本身。

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
/**
* 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 TreeNode pruneTree(TreeNode root) {
if(root == null) return null;
root.left = pruneTree(root.left);
root.right = pruneTree(root.right);
if(root.left == null && root.right == null && root.val == 0) return null;
else return root;
}
}

Solution 2

DFS搜索,返回子节点和自己中是否包含1。
如果节点为null,则返回false。
如果自己为1,则返回true。
否则返回两个子节点中是否有true。

BFS搜索,根据每个节点的子节点是否包含1来决定左右子节点是否保存。
如果没有1,则将对应的子节点修改为null。

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
/**
* 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 TreeNode pruneTree(TreeNode root) {
if(!hasOne(root)) return null;
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()){
TreeNode curr = q.poll();
if(hasOne(curr.left)) q.add(curr.left);
else curr.left = null;
if(hasOne(curr.right)) q.add(curr.right);
else curr.right = null;
}
return root;
}

private boolean hasOne(TreeNode root){
if(root == null) return false;
if(root.val == 1) return true;
else return hasOne(root.left) || hasOne(root.right);
}
}