大提莫


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

  • 搜索

637. Average of Levels in Binary Tree

发表于 2017-07-13 | 分类于 刷题总结

Given a non-empty binary tree, return the average value of the nodes on each level in the form of an array.

Example 1:

1
2
3
4
5
6
7
8
9
10
Input:
3
/ \
9 20
/ \
15 7
Output: [3, 14.5, 11]
Explanation:
The average value of nodes on level 0 is 3, on level 1 is 14.5, and on level 2 is 11. Hence return [3, 14.5, 11].

Note:

The range of node's value is in the range of 32-bit signed integer.

解法1:

一个bfs解决问题。
要注意的是当中的加和可能会overflow,要用long。
C++

1

Java

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
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<Double>();
if (root == null) {
return res;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
long sum = 0;
for (int i = 0; i < size; i++) {
TreeNode current = queue.poll();
sum += current.val;
if (current.left != null) {
queue.offer(current.left);
}
if (current.right != null) {
queue.offer(current.right);
}
}
res.add((double)sum / size);
}
return res;
}
}

368. Largest Divisible Subset

发表于 2017-07-13 | 分类于 刷题总结

Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.

If there are multiple solutions, return any subset is fine.

Example 1:

nums: [1,2,3]

Result: [1,2] (of course, [1,3] will also be ok)

Example 2:

nums: [1,2,4,8]

Result: [1,2,4,8]

解法1:

思路是:
if a < b then a % b != 0 for all a , b > 0
所以只需要对与一个数,只要从大往小找小于他的数即可。
第二步:
先把数组排序,便于分析。
对于排好序的数组,我们可以计算出对于每一个数字,数组中存在的可以整除他的数的最大个数。
这可以用一个dp完成。
统计出最大的个数的同时,如果我们维护另外一个数组,记录能被整除且sequence最长的那个数的index,就能在之后把整条链提取出来。

C++

1

Java

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
public class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> res = new ArrayList<Integer>();
if (nums == null || nums.length == 0) {
return res;
}
Arrays.sort(nums); // sort the array first
int n = nums.length;
int[] dp = new int[n];
int[] index = new int[n]; // index stores the corresponding next item in the longest subsequence
Arrays.fill(dp, 1);
Arrays.fill(index, -1);
int max = 1;
int maxIndex = 0;
for (int i = 1; i < n; i++) {
for (int j = i - 1; j >= 0; j--) {
if (nums[i] % nums[j] == 0) {
if (dp[j] + 1 > dp[i]) {
dp[i] = dp[j] + 1; // update the dp array
index[i] = j;
}
}
}
if (dp[i] > max) {
max = dp[i];
maxIndex = i;
}
}
// maxIndex
for (int i = maxIndex; i != -1; i = index[i]) {
res.add(nums[i]);
}
return res;
}
}

这题如果改成,求最长的subset的长度,使得subset中每两个数字都能保证其中一个被整除,那么这就是一个经典的dp问题。
这题的难点是在这个的基础上要求出这个subset。对于这种问题,一般可以采取的方法就是在dp的过程中记录下每一个点的optimal解法相对应的位置。
这题就是这样,dp[i]记录下对于第i个点,他们之前的0到i-1个点对应的能被其整除的数字的个数,当这个个数被更新的时候,记录下其所对应的位置。
当扫描结束一遍之后,我们也得到了对应于最大答案的subset中每一个点的位置。

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
class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
List<Integer> res = new ArrayList<>();
if (nums == null || nums.length == 0) {
return res;
}
int n = nums.length;
Arrays.sort(nums);
int[] dp = new int[n]; // stores the number of longest subsequence of the array that all elements can be divisible
dp[0] = 1;
int[] tracks = new int[n];
Arrays.fill(tracks, -1);
int max = 0;
for (int i =1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i] % nums[j] == 0) {
if (dp[j] + 1 >= dp[i]) {
dp[i] = dp[j] + 1;
tracks[i] = j;
}
}
}
if (dp[i] >= dp[max]) {
max = i;
}
}
// start from i and trace back to get the list
for (int i = max; i >= 0; i = tracks[i]) {
res.add(nums[i]);
}
return res;
}
}

572. Subtree of Another Tree

发表于 2017-07-13 | 分类于 刷题总结

Given two non-empty binary trees s and t, check whether tree t has exactly the same structure and node values with a subtree of s. A subtree of s is a tree consists of a node in s and all of this node’s descendants. The tree s could also be considered as a subtree of itself.

Example 1:
Given tree s:

1
2
3
4
5
6
7
8
9
10
11
3
/ \
4 5
/ \
1 2
Given tree t:
4
/ \
1 2

Return true, because t has the same structure and node values with a subtree of s.

Example 2:
Given tree s:

1
2
3
4
5
6
7
8
9
10
11
12
13
3
/ \
4 5
/ \
1 2
/
0
Given tree t:
4
/ \
1 2

Return false.

解法1:

很简单的一个递归算法。如果当前节点数值一样,那么先判断是否identical,如果不是,考虑left, 考虑right是否和target tree存在subset关系。

C++

1

Java

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
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public boolean isSubtree(TreeNode s, TreeNode t) {
if (s == null && t == null) {
return true;
} else if (s == null || t == null) {
return false;
}
if (s.val == t.val) {
if (identical(s, t)) {
return true;
}
}
return isSubtree(s.left, t) || isSubtree(s.right, t);
}
private boolean identical(TreeNode s, TreeNode t) {
if (s == null && t == null) {
return true;
} else if (s == null || t == null) {
return false;
}
if (s.val != t.val) {
return false;
}
return identical(s.left, t.left) && identical(s.right, t.right);
}
}

115. Distinct Subsequences

发表于 2017-07-13 | 分类于 刷题总结

Given a string S and a string T, count the number of distinct subsequences of S which equals T.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, “ACE” is a subsequence of “ABCDE” while “AEC” is not).

Here is an example:
S = “rabbbit”, T = “rabbit”

Return 3.

解法1:O(NM)

dp[i][j]表示的是s[0,i]和t[0,j]的匹配答案。
递推关系可以分为s[i] == t[j] 和不等的两种情况
如果相等,那么既可以是包括i, 那么就是需要知道(i-1,j-1)的结果;也可以是不包括j, 那么就需要知道(i -1, j)的结果
如果不相等,只要(i - 1, j)就可以了。
C++

1

Java

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
public class Solution {
public int numDistinct(String s, String t) {
int n = s.length();
int m = t.length();
int[][] dp = new int[n + 1][m + 1];
for (int i = 0; i <= n; i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[n][m];
}
}

377. Combination Sum IV

发表于 2017-07-13 | 分类于 刷题总结

Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.

Example:

1
2
3
4
5
6
7
8
9
10
11
nums = [1, 2, 3]
target = 4
The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

Note that different sequences are counted as different combinations.

Therefore the output is 7.

Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?

解法1:O(N) 解法 

dp[i]表示的是target为i时一共的解法。
对于如果target较大的话,可以先把nums排一下序。然后在内层循环里面当i<num的时候直接break就可以了。
follow up:如果负数被允许的话,解答可能是infinite。比如[-1,1],target为1的情况。
这个时候需要限制比如每个元素用几次之类的。

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Solution {
public int combinationSum4(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int[] dp = new int[target + 1];
dp[0] = 1;
for (int i = 0; i <= target; i++) {
for (int num : nums) {
if (i >= num) {
dp[i] += dp[i - num];
}
}
}
return dp[target];
}
}

300. Longest Increasing Subsequence

发表于 2017-07-11 | 分类于 刷题总结

Given an unsorted array of integers, find the length of longest increasing subsequence.

For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O(n2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?

解法1:O(N^2)

经典dp, dp[i]是到第i个数字的最大递增subsequence, 那么dp[i] = Max(dp[k1], dp[k2], dp[k3]…) + 1, nums[i] > nums[kn]

C+,

1

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Solution {
public int lengthOfLIS(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int[] dp = new int[nums.length];
dp[0] = 1;
int res = 1;
for (int i = 1; i < nums.length; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
res = Math.max(res, dp[i]);
}
return res;
}
}

解法2:O(NlogN)

解释参考leetcode 的答案解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
In this approach, we scan the array from left to right. We also make use of a dpdpdp array initialized with all 0's. This dpdpdp array is meant to store the increasing subsequence formed by including the currently encountered element. While traversing the numsnumsnums array, we keep on filling the dpdpdp array with the elements encountered so far. For the element corresponding to the jthj^{th}j​th​​ index (nums[j]nums[j]nums[j]), we determine its correct position in the dpdpdp array(say ithi^{th}i​th​​ index) by making use of Binary Search(which can be used since the dpdpdp array is storing increasing subsequence) and also insert it at the correct position. An important point to be noted is that for Binary Search, we consider only that portion of the dpdpdp array in which we have made the updations by inserting some elements at their correct positions(which remains always sorted). Thus, only the elements upto the ithi^{th}i​th​​ index in the dpdpdp array can determine the position of the current element in it. Since, the element enters its correct position(iii) in an ascending order in the dpdpdp array, the subsequence formed so far in it is surely an increasing subsequence. Whenever this position index iii becomes equal to the length of the LIS formed so far(lenlenlen), it means, we need to update the lenlenlen as len=len+1len = len + 1len=len+1.
Note: dpdpdp array does not result in longest increasing subsequence, but length of dpdpdp array will give you length of LIS.
Consider the example:
input: [0, 8, 4, 12, 2]
dp: [0]
dp: [0, 8]
dp: [0, 4]
dp: [0, 4, 12]
dp: [0 , 2, 12] which is not the longest increasing subsequence, but length of dpdpdp array results in length of Longest Increasing Subsequence.

lang: java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
int len = 0;
for (int num : nums) {
int i = Arrays.binarySearch(dp, 0, len, num);
if (i < 0) {
i = -(i + 1);
}
dp[i] = num;
if (i == len) {
len++;
}
}
return len;
}
}

351. Android Unlock Patterns

发表于 2017-07-11 | 分类于 刷题总结

Given an Android 3x3 key lock screen and two integers m and n, where 1 ≤ m ≤ n ≤ 9, count the total number of unlock patterns of the Android lock screen, which consist of minimum of m keys and maximum n keys.

Rules for a valid pattern:

Each pattern must connect at least m keys and at most n keys.
All the keys must be distinct.
If the line connecting two consecutive keys in the pattern passes through any other keys, the other keys must have previously selected in the pattern. No jumps through non selected key is allowed.
The order of keys used matters.
alt text
Explanation:

| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |

Invalid move: 4 - 1 - 3 - 6
Line 1 - 3 passes through key 2 which had not been selected in the pattern.

Invalid move: 4 - 1 - 9 - 2
Line 1 - 9 passes through key 5 which had not been selected in the pattern.

Valid move: 2 - 4 - 1 - 3 - 6
Line 1 - 3 is valid because it passes through key 2, which had been selected in the pattern

Valid move: 6 - 5 - 4 - 1 - 9 - 2
Line 1 - 9 is valid because it passes through key 5, which had been selected in the pattern.

Example:
Given m = 1, n = 1, return 9.

解法1:

这题一拿到感觉是dp或者是dfs的题目。用dp想不出状态方程看来只能用dfs试一下。
dfs的话最核心的思想就是每次往目标前进一步,如果成功则再继续探寻。
这个问题的一部是要看上一步和当前一步是否构成一个合适的movement.
一定是:
1. 相邻的
2. 对线的
3. 不相邻但是当中的数字已经被访问过了

那么用一个数组维护访问过的数字,同时维护一个上次访问的数字和当前的数字,以便判断一个move是否合适。
对于每一个数字进行dfs遍历,每前进一步就把所剩的步数-1.
C++

1

Java

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
public class Solution {
public int numberOfPatterns(int m, int n) {
int sum = 0;
for (int i = m; i <= n; i++) {
boolean[] visited = new boolean[9]; // initialize the array
sum += dfs(visited, -1, i);
}
return sum;
}
private boolean isValidMove(boolean[] visited, int last, int current) {
if (visited[current]) {
return false;
}
if (last == -1) {
// First move, always true
return true;
}
if ((last + current) % 2 == 1) {
return true;
}
int row_last = last / 3;
int row_current = current / 3;
int col_last = last % 3;
int col_current = current % 3;
// if (row_last == row_current && (Math.abs(col_last - col_current) == 1)) {
// return true;
// }
// if (col_last == col_current && (Math.abs(row_last - row_current) == 1)) {
// return true;
// }
int mid = (last + current) / 2;
if (mid == 4) {
return visited[mid]; // diagonal
}
if (row_last != row_current && col_last != col_current) {
return true;
}
return visited[mid];
}
private int dfs(boolean[] visited, int last, int len) {
// last is the last visited number
// len is the remaining length of required key string
if (len == 0) {
return 1;
}
// record the sum
int sum = 0;
for (int i = 0; i < 9; i++) {
// Move from last to i
if (isValidMove(visited, last, i)) {
visited[i] = true;
sum += dfs(visited, i, len - 1);
visited[i] = false;
}
}
return sum;
}
}

解法2:

由于可能的跳跃是有限的,可以用一个table来存储合法的跳跃path。这样可以简化很多检查一个move是否合法的code。
每次DFS的时候从一个点开始,找出可能的path。同时利用对称性,1,3,7,9是一样的;2,4,6,8是一样的。5单独一个。

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
public class Solution {
// cur: the current position
// remain: the steps remaining
int DFS(boolean vis[], int[][] skip, int cur, int remain) {
if(remain < 0) return 0;
if(remain == 0) return 1;
vis[cur] = true;
int rst = 0;
for(int i = 1; i <= 9; ++i) {
// If vis[i] is not visited and (two numbers are adjacent or skip number is already visited)
if(!vis[i] && (skip[cur][i] == 0 || (vis[skip[cur][i]]))) {
rst += DFS(vis, skip, i, remain - 1);
}
}
vis[cur] = false;
return rst;
}
public int numberOfPatterns(int m, int n) {
// Skip array represents number to skip between two pairs
int skip[][] = new int[10][10];
skip[1][3] = skip[3][1] = 2;
skip[1][7] = skip[7][1] = 4;
skip[3][9] = skip[9][3] = 6;
skip[7][9] = skip[9][7] = 8;
skip[1][9] = skip[9][1] = skip[2][8] = skip[8][2] = skip[3][7] = skip[7][3] = skip[4][6] = skip[6][4] = 5;
boolean vis[] = new boolean[10];
int rst = 0;
// DFS search each length from m to n
for(int i = m; i <= n; ++i) {
rst += DFS(vis, skip, 1, i - 1) * 4; // 1, 3, 7, 9 are symmetric
rst += DFS(vis, skip, 2, i - 1) * 4; // 2, 4, 6, 8 are symmetric
rst += DFS(vis, skip, 5, i - 1); // 5
}
return rst;
}
}

30. Substring with Concatenation of All Words

发表于 2017-07-11 | 分类于 刷题总结

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.

For example, given:
s: “barfoothefoobarman”
words: [“foo”, “bar”]

You should return the indices: [0,9].
(order does not matter).

解法1:

也是滑动窗口的思路,第一层循环是对于起始点的遍历。起始点可以从0到word的长度-1。
之后就是一个词一个词的向右进。同时统计每一个词出现的次数。
C++

1

Java

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
public class Solution {
public List<Integer> findSubstring(String s, String[] words) {
List<Integer> res = new ArrayList<Integer>();
if (words == null || words.length == 0) {
return res;
}
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> currentMap = new HashMap<>();
for (String word : words) {
map.put(word, map.getOrDefault(word, 0) + 1);
}
int len = s.length();
int N = words.length;
int M = words[0].length();
for (int i = 0; i < M; i++) {
int count = 0;
int start = i; // record the start index of the substring
int left = start, right = left + M;
while (right <= len) {
String current = s.substring(left, right);
if (map.containsKey(current)) {
currentMap.put(current, currentMap.getOrDefault(current, 0) + 1);
if (currentMap.get(current) <= map.get(current)) count++; // find a matched word
while (currentMap.get(current) > map.get(current)) {
String temp = s.substring(start, start + M);
currentMap.put(temp, currentMap.get(temp) - 1);
start += M; // update the start of the substring
if (currentMap.get(temp) < map.get(temp)) count--;
}
if (count == N) {
res.add(start);
String temp = s.substring(start, start + M);
currentMap.put(temp, currentMap.get(temp) - 1);
count--;
start += M; // update the start of the substring
}
} else {
count = 0;
currentMap.clear();
start = right;
}
left = right;
right += M;
}
currentMap.clear();
}
return res;
}
}

340. Longest Substring with At Most k Distinct Characters

发表于 2017-07-11 | 分类于 刷题总结

Given a string, find the length of the longest substring T that contains at most k distinct characters.

For example, Given s = “eceba” and k = 2,

T is “ece” which its length is 3.

解法1:O(N)

滑动窗口的解法。
C++

1

Java

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
public class Solution {
public int lengthOfLongestSubstringKDistinct(String s, int k) {
HashMap<Character, Integer> map = new HashMap<>();
int count = 0, start = 0, end = 0;
int res = 0;
while (end < s.length()) {
char current = s.charAt(end);
map.put(current, map.getOrDefault(current, 0) + 1);
if (map.get(current) == 1) {
count++;
}
end++; // move 1 position forward
while (count > k) {
char prev = s.charAt(start);
map.put(prev, map.get(prev) - 1);
if (map.get(prev) == 0) {
count--;
}
start++;
}
res = Math.max(res, end - start);
}
return res;
}
}

159. Longest Substring with At Most Two Distinct Characters

发表于 2017-07-11 | 分类于 刷题总结

Given a string, find the length of the longest substring T that contains at most 2 distinct characters.

For example, Given s = “eceba”,

T is “ece” which its length is 3.

解法1:O(N)

这题是sliding window的一个例题。要掌握一下模板。这题和另一题at most k distinct characters的解法一致。
主要的思路就是维护一个hashmap存取每一个元素出现的次数,如果为1的话,就说明是新入的元素,总个数要+1
同时维护一个start指针来标记左面的边界,每次找到一个符合标准的答案时,更新最长的长度。
C++

1

Java

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
public class Solution {
public int lengthOfLongestSubstringTwoDistinct(String s) {
HashMap<Character, Integer> map = new HashMap<>();
int count = 0, start = 0, end = 0;
int res = 0;
while (end < s.length()) {
char current = s.charAt(end);
map.put(current, map.getOrDefault(current, 0) + 1);
if (map.get(current) == 1) {
// new character
count++;
}
end++; // move end 1 position forward
while (count > 2) {
char prev = s.charAt(start);
map.put(prev, map.get(prev) -1 );
if (map.get(prev) == 0) {
// Removed one character
count--;
}
start++;
}
res = Math.max(res, end - start);
}
return res;
}
}

1…141516…46
Bigteemo

Bigteemo

454 日志
4 分类
70 标签
© 2017 Bigteemo
由 Hexo 强力驱动
主题 - NexT.Mist