leetcode刷题总结801-850
801. 使序列递增的最小交换次数
描述:
思路:
class Solution { public: int minSwap(vector<int>& A, vector<int>& B) { int res = 0; vector<vector<int>> dp(A.size(),vector(2,0)); dp[0][0] = 0; dp[0][1] = 1; for(int i = 1;i < A.size();i++) { if(A[i-1]<A[i]&&B[i-1]<B[i]){ if(A[i-1]<B[i] && B[i-1]<A[i]){//任意交换或者不交换,取最优值 dp[i][0] = min(dp[i-1][0],dp[i-1][1]); dp[i][1] = min(dp[i-1][0],dp[i-1][1])+1; }else{ dp[i][0] = dp[i-1][0];//不交换,则上个位置也不能交换 dp[i][1] = dp[i-1][1]+1; //交换,则上个位置也必须交换 } }else{ dp[i][0] = dp[i-1][1];// 不交换,则上个位置必须交换 dp[i][1] = dp[i-1][0]+1;// 交换,则上个位置不能交换 } } return min(dp[A.size()-1][0],dp[A.size()-1][1]); } };
807. 保持城市天际线
描述:
思路:先对 从上到下,从左到右统计。统计完后对每个坐标进行 可以增添高度的 统计。
808. 分汤
描述:
思路:
转移方程:dp[i][j] = 0.25 * (dp[i-100][j] + dp[i-75][j-25] + dp[i-50][j-50] + dp[i-75][j-25])
将N缩小为原来的25分之一的转移方程:dp[i][j] = 0.25 * (dp[i-4][j] + dp[i-3][j-1] + dp[i-2][j-2] + dp[i-3][j-1])
809. 情感丰富的文字
描述:
思路:
我们首先将 S 拆分成若干组相同的字母,并存储每组字母的长度。例如当 S 为 abbcccddddaaaaa 时,可以得到 5 组字母,它们分别为 abcda,长度为 [1, 2, 3, 4, 5]。
对于 words 中的每个单词 word,如果它可以扩张得到 S,那么它必须和 S 有相同的字母组。对于每一组字母,假设 S 中有 c1 个,word 中有 c2 个,那么会有下面几种情况:
如果 c1 < c2,那么 word 不能扩张得到 S;
如果 c1 >= 3,那么只要添加 c1 - c2 个字母即可;
如果 c1 < 3,由于在扩张时至少需要添加到 3 个字母,所以此时不能添加字母,必须有 c1 == c2。
如果 word 的包含的字母组中的每个字母都满足上述情况,那么 word 可以扩张得到 S。
813. 最大平均值和的分组
描述:
思路:
dp(i, k) = max(dp(j, k - 1) + average(j + 1, i))
dp(i, 0) = average(0, i)
814. 二叉树剪枝
描述:
思路:
class Solution { public TreeNode pruneTree(TreeNode root) { return containsOne(root) ? root : null; } public boolean containsOne(TreeNode node) { if (node == null) return false; boolean a1 = containsOne(node.left); boolean a2 = containsOne(node.right); if (!a1) node.left = null; if (!a2) node.right = null; return node.val == 1 || a1 || a2; } }
815. 公交路线
描述:
思路:广度优先。。。看到最少 最低 首先想到 广度。
817. 链表组件
描述:
思路:线性扫描即可。
820. 单词的压缩编码
描述:
思路:先set。然后对set去除所有substring(i,length)的字符。然后再计算+1.
825. 适龄的朋友
描述:
思路:
class Solution { public int numFriendRequests(int[] ages) { int[] count = new int[121]; for (int age: ages) count[age]++; int ans = 0; for (int ageA = 0; ageA <= 120; ageA++) { int countA = count[ageA]; for (int ageB = 0; ageB <= 120; ageB++) { int countB = count[ageB]; if (ageA * 0.5 + 7 >= ageB) continue; if (ageA < ageB) continue; if (ageA < 100 && 100 < ageB) continue; ans += countA * countB; if (ageA == ageB) ans -= countA; } } return ans; } }
829. 连续整数求和
描述:
思路:
class Solution { public int consecutiveNumbersSum(int N) { int ans = 0; for (int start = 1; start <= N; ++start) { int target = N, x = start; while (target > 0) target -= x++; if (target == 0) ans++; } return ans; } }
836. 矩形重叠
描述:
思路:
class Solution {
public boolean isRectangleOverlap(int[] rec1, int[] rec2) {
return !(rec1[2] <= rec2[0] || // left
rec1[3] <= rec2[1] || // bottom
rec1[0] >= rec2[2] || // right
rec1[1] >= rec2[3]); // top
}
}
837. 新21点
描述:
思路:
//注意动态规划中规划的重复,比如这个题就有重复,可以用窗口完成之前的记录 var new21Game = function (N, K, W) { let dp = new Array(N + 1).fill(0) dp[0] = 1 let windowSum = 0 for (let i = 1; i < N + 1; i++) { if (i - W - 1 >= 0) { // 甩掉的dp[i - W - 1]要存在呀 windowSum -= dp[i - W - 1] // 甩掉上一次window左端 } if (i - 1 < K) { // 新纳入的dp[i - 1]要存在呀,分数i<=K,i-1<K windowSum += dp[i - 1]// 纳入上一次window的右侧一项 } dp[i] = windowSum * (1 / W) } let res = 0 for (let i = K; i <= N; i++) { res += dp[i] } return res };
841. 钥匙和房间
描述:
思路:
class Solution { public boolean canVisitAllRooms(List<List<Integer>> rooms) { boolean[] seen = new boolean[rooms.size()]; seen[0] = true; Stack<Integer> stack = new Stack(); stack.push(0); //At the beginning, we have a todo list "stack" of keys to use. //'seen' represents at some point we have entered this room. while (!stack.isEmpty()) { // While we have keys... int node = stack.pop(); // Get the next key 'node' for (int nei: rooms.get(node)) // For every key in room # 'node'... if (!seen[nei]) { // ...that hasn't been used yet seen[nei] = true; // mark that we've entered the room stack.push(nei); // add the key to the todo list } } for (boolean v: seen) // if any room hasn't been visited, return false if (!v) return false; return true; } }
842. 将数组拆分成斐波那契序列
描述:
思路:回溯算法。
845. 数组中的最长山脉
描述:
思路:找到山顶(局部最大值),然后对每个山峰进行确定。
846. 一手顺子
描述:
思路:
使用 TreeMap 或 dict 记录每种牌的数量 {card: number of copies of card}。
然后反复执行以下步骤:找到最小的一张牌(假设是 x),然后试图将 x, x+1, x+2, ..., x+W-1 这些牌的计数减 1。如果每次都能找到这样的组且最终手里无牌,那么分组成功,否则失败。
848. 字母移位
描述:
思路:统计每个字母的shift次数。
849. 到最近的人的最大距离
描述:
思路:从左到右。从右到左。min. max