207场周赛
##1.重新排列单词间的空格
模拟题,细心即可。
1 | class Solution { |
2 | public String reorderSpaces(String text) { |
3 | char[] str = text.toCharArray(); |
4 | int spacenum = 0; |
5 | int wordnum = 0; |
6 | List<String> wordlist = new ArrayList<String>(); |
7 | for(int i=0; i<str.length; i++){ |
8 | if(str[i] == ' '){ |
9 | spacenum++; |
10 | }else{ |
11 | int j=i; |
12 | while(i<str.length){ |
13 | |
14 | if(str[i]>='a' && str[i]<='z'){ |
15 | i++; |
16 | }else { |
17 | spacenum++; |
18 | break; |
19 | } |
20 | } |
21 | String word = text.substring(j, i); |
22 | wordlist.add(word); |
23 | } |
24 | } |
25 | |
26 | wordnum = wordlist.size(); |
27 | if(wordnum - 1==0){ |
28 | StringBuilder sb = new StringBuilder(); |
29 | char[] space = new char[spacenum]; |
30 | Arrays.fill(space, ' '); |
31 | sb.append(wordlist.get(0)); |
32 | sb.append(space); |
33 | return sb.toString(); |
34 | } |
35 | int a = spacenum / (wordnum-1); |
36 | int b = spacenum % (wordnum-1); |
37 | char[] aa = new char[a]; |
38 | char[] bb = new char[b]; |
39 | Arrays.fill(aa, ' '); |
40 | Arrays.fill(bb, ' '); |
41 | StringBuilder sb = new StringBuilder(); |
42 | for(int i=0; i<wordlist.size(); i++){ |
43 | String word = wordlist.get(i); |
44 | if(i == wordlist.size()-1){ |
45 | sb.append(word); |
46 | }else { |
47 | sb.append(word); |
48 | sb.append(aa); |
49 | } |
50 | } |
51 | |
52 | sb.append(bb); |
53 | return sb.toString(); |
54 | } |
55 | } |
复杂度分析:
- 时间复杂度:$O(N)$。
- 空间复杂度:$O(N)$。
2.拆分字符串使唯一子字符串的数目最大
用一个集合存储每个出现过的子字符串。对于每个位置上的字符串,都有拆分和不拆分两种选择,可以选择拆分,如果不满足条件(拆分出的子字符串未出现过)就回溯。
1 | class Solution { |
2 | int max = 0; |
3 | Set<String> set = new HashSet<String>(); |
4 | public int maxUniqueSplit(String s) { |
5 | dfs(0,0,1,s); |
6 | return max; |
7 | } |
8 | |
9 | public void dfs(int start, int end, int res, String s){ |
10 | if(end == s.length()-1){ |
11 | if(set.contains(s.substring(start,end+1))){ |
12 | return; |
13 | }else { |
14 | max = Math.max(max, res); |
15 | return; |
16 | } |
17 | } |
18 | String cur = s.substring(start, end+1); |
19 | if(!set.contains(cur)){ |
20 | set.add(cur); |
21 | dfs(end+1, end+1, res+1, s); |
22 | set.remove(cur); |
23 | } |
24 | dfs(start, end+1, res, s); |
25 | } |
26 | } |
复杂度分析:
- 时间复杂度:$O(N)$。
- 空间复杂度:$O(N)$。
3.矩阵的最大非负积
因为最大的结果可能由一个正数乘以一个正数得到,也可能由一个负数乘以一个负数得到,因此需要分别记录最大值和最小值。当前位置[x,y]
的最大值和最小值由[x-1,y]
和[x,y-1]
与当前位置的值grid[x][y]
得到,由此可以得到状态转移方程。
1 | class Solution { |
2 | public int maxProductPath(int[][] grid) { |
3 | int m = grid.length; |
4 | int n = grid[0].length; |
5 | long[][] pos = new long[m][n]; |
6 | long[][] neg = new long[m][n]; |
7 | long mod = (long)(1e9+7); |
8 | pos[0][0] = neg[0][0] = grid[0][0]; |
9 | for(int i=1; i<m; i++){ |
10 | pos[i][0] = pos[i-1][0]*grid[i][0]; |
11 | neg[i][0] = neg[i-1][0]*grid[i][0]; |
12 | } |
13 | for(int j=1; j<n; j++){ |
14 | pos[0][j] = pos[0][j-1]*grid[0][j]; |
15 | neg[0][j] = neg[0][j-1]*grid[0][j]; |
16 | } |
17 | for(int i=1; i<m; i++){ |
18 | for(int j=1; j<n; j++){ |
19 | long a = pos[i-1][j] * grid[i][j]; |
20 | long b = neg[i-1][j] * grid[i][j]; |
21 | long c = pos[i][j-1] * grid[i][j]; |
22 | long d = neg[i][j-1] * grid[i][j]; |
23 | pos[i][j] = Math.max(Math.max(a,b), Math.max(c,d)); |
24 | neg[i][j] = Math.min(Math.min(a,b), Math.min(c,d)); |
25 | } |
26 | } |
27 | int res = (int) Math.max(pos[m-1][n-1]%mod, neg[m-1][n-1]%mod); |
28 | return (res<0)? -1:res; |
29 | } |
30 | } |
复杂度分析:
- 时间复杂度:$O(N*M)$。
- 空间复杂度:$O(N*M)$。
4.连通两组点的最小成本
问题等价于: 在一个矩阵中选取一些值, 满足矩阵的每一行和每一列都至少有一个元素被选中, 同时选中元素的总和最小 (此矩阵就是 cost
矩阵)。
由于矩阵的列数较少, 我们可以用状压 DP 来表示每一行的选取情况, 假设矩阵有 m 行 n 列, 那么我们维护一个 DP 矩阵 dp[m][1 << n]
,dp[i][j]
表示当前选取到第 $i$ 行, 每列的选取状况为 $j$ 时总的最小开销, 其中 $j$ 的第 $k$ 位为 $1$ 即表示第 $k$ 列已经被选取过了. 那么状态转移方程为
$dp[i][j|k] = Math.min(dp[i][j|k], dp[i - 1][k] + costMatrix[i][j])$
其中 $costMatrix[i][j] $表示第 $i$ 行选取状况为 $j$ 时该行被选取得元素总和。
1 | class Solution { |
2 | public int connectTwoGroups(List<List<Integer>> cost) { |
3 | int m = cost.size(), n = cost.get(0).size(); |
4 | int[][] costMatrix = new int[m][1 << n]; |
5 | for (int k = 0; k < m; k++) { |
6 | for (int i = 0; i < (1 << n); i++) { |
7 | int sum = 0; |
8 | for (int j = 0; j < n; j++) { |
9 | if ((i & (1 << j)) > 0) |
10 | sum += cost.get(k).get(j); |
11 | } |
12 | costMatrix[k][i] = sum; |
13 | } |
14 | } |
15 | int[][] dp = new int[m][1 << n]; |
16 | for (int i = 1; i < m; i++) |
17 | Arrays.fill(dp[i], Integer.MAX_VALUE); |
18 | dp[0] = costMatrix[0]; |
19 | for (int i = 1; i < m; i++) |
20 | for (int j = 1; j < (1 << n); j++) |
21 | for (int k = 1; k < (1 << n); k++) |
22 | dp[i][j | k] = Math.min(dp[i][j | k], dp[i - 1][k] + costMatrix[i][j]); |
23 | return dp[m - 1][(1 << n) - 1]; |
24 | } |
25 | } |
复杂度分析:
- 时间复杂度:$O(M2^N2^N)$。
- 空间复杂度:$O(N*M)$。