253. 会议室 II(NO)

279. 完全平方数

class Solution {
public int numSquares(int n) {
// dp[i] : 组成和为 i 的最少完全平方数个数
// base case: dp[0] = 0;
int[] dp = new int[n + 1]; for (int i = 1; i < n + 1; i++) {
// 最大值即为i
dp[i] = i; // 转移方程
for (int j = 1; i - j*j >= 0; j++) {
dp[i] = Math.min(dp[i], dp[i - j*j] + 1);
}
} return dp[n];
}
}

推荐题解:画解算法:279. 完全平方数

283. 移动零

思路一:双指针,i 指向 非0 元素的下一个待插入位置,j 遍历数组,每次遇到 非0 元素就插入 i 指向的位置并一起向后移动,最后将 i 及其后面全部补0即可。

class Solution {
public void moveZeroes(int[] nums) {
int len = nums.length; int i = 0; // i 指向 非0 元素的下一个待插入位置 // j 一直向后遍历,每次遇到 非0 元素就插入i指向的位置并一起向后移动
for (int j = 0; j < len; j++) {
if (nums[j] != 0) {
nums[i++] = nums[j];
}
} // i 及其后面全部补0即可
for ( ; i < len; i++) {
nums[i] = 0;
}
}
}

思路二:双指针,i 指向 非0 元素的下一个待插入位置,j 遍历数组,每次遇到 非0 元素就与 i 指向元素交换并一起向后移动,最后 [0, i) 之前全部为非0元素,(i, j)之间全部为 0。

class Solution {
public void moveZeroes(int[] nums) {
int len = nums.length; int i = 0; // i 指向 非0 元素的下一个待插入位置 // 每次遇到 非0 元素就与 i 指向元素交换并一起向后移动
for (int j = 0; j < len; j++) {
if (nums[j] != 0) {
swap(nums, i, j);
i++;
}
} } private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}

287. 寻找重复数

该题最简单的思路便是使用set,但题目要求空间复杂度为O(1)。另外一种简单思路是使用排序,然后检查重复数即可,但题目又要求时间复杂度为O(nlogn),且不能修改原数组。面试时我们应该询问面试官 时间 和 空间复杂度 要求之后再确定具体使用的方法。

思路一:快慢指针,建议先刷:141. 环形链表142. 环形链表 II

推荐题解:287.寻找重复数

class Solution {
public int findDuplicate(int[] nums) {
int slow = 0;
int fast = nums[slow]; while (slow != fast) {
fast = nums[nums[fast]];
slow = nums[slow];
} fast = nums[slow];
slow = 0; while (slow != fast) {
fast = nums[fast];
slow = nums[slow];
} return slow;
}
}

思路二:将所有元素放置在其值减1的下标位置。如:1 应该放置在 0 位置,3 应该放置在 2 位置,这样,重复的元素至少有一个无法放置在对应位置。思路来自:剑指 Offer 03. 数组中重复的数字

class Solution {
public int findDuplicate(int[] nums) {
int len = nums.length; for (int i = 0; i < len - 1; i++) {
// 如果元素的 值 和 下标 不匹配,则将其交换至对的位置
while ((nums[i] - 1) != i) {
// 如果发现待交换的两个元素相同则直接返回 如:[3,1,3,4,2]
if (nums[i] == nums[nums[i] - 1]) {
return nums[i];
}
swap(nums, i, nums[i] - 1);
}
} // 通常,最后一个元素为重复元素
return nums[len - 1];
} private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}

备注:该方法修改了原来的数组。时间复杂度为O(n),因为每个元素至多交换一次,空间复杂度为O(1)

297. 二叉树的序列化与反序列化

思路一:使用先序遍历进行序列化(dfs)

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec { // Encodes a tree to a single string.
public String serialize(TreeNode root) {
if (root == null) {
return "#";
} String leftSerial = serialize(root.left);
String rightSerial = serialize(root.right); return root.val + "," + leftSerial + "," + rightSerial;
} // Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] strs = data.split(",");
Deque<String> queue = new LinkedList<>();
for (String str : strs) {
queue.offer(str);
} return deserialize(queue);
} private TreeNode deserialize(Deque<String> queue) { String rootVal = queue.poll();
if (rootVal.equals("#")) {
return null;
} TreeNode root = new TreeNode(Integer.parseInt(rootVal));
root.left = deserialize(queue);
root.right = deserialize(queue); return root;
}
} // Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

思路二:使用层次遍历进行序列化(bfs)

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Codec { // Encodes a tree to a single string.
public String serialize(TreeNode root) {
Deque<TreeNode> queue = new LinkedList<>();
StringBuilder sb = new StringBuilder(); queue.offer(root);
while (!queue.isEmpty()) {
TreeNode temp = queue.poll(); if (temp != null) {
sb.append(temp.val).append(","); queue.offer(temp.left);
queue.offer(temp.right);
} else {
sb.append("#").append(",");
}
}
System.out.println(sb.toString());
return sb.toString();
} // Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
String[] strs = data.split(",");
Deque<TreeNode> queue = new LinkedList<>(); int i = 0;
if (strs[i].equals("#")) return null; TreeNode root = new TreeNode(Integer.parseInt(strs[i++]));
queue.offer(root); while (!queue.isEmpty()) {
TreeNode temp = queue.poll(); String leftVal = strs[i++];
String rightVal = strs[i++]; if (!leftVal.equals("#")) {
TreeNode leftChild = new TreeNode(Integer.parseInt(leftVal));
temp.left = leftChild;
queue.offer(leftChild);
}
if (!rightVal.equals("#")) {
TreeNode rightChild = new TreeNode(Integer.parseInt(rightVal));
temp.right = rightChild;
queue.offer(rightChild);
}
} return root;
} } // Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

推荐题解:『手画图解』剖析DFS、BFS解法 | 二叉树的序列化与反序列化

300. 最长递增子序列

思路:动态规划

状态:以当前字符结尾的字符串中最长递增子序列的长度

转移方程:dp[i] = max(dp[j] + 1, dp[i]),其中 j < inums[j] < nums[i]

base case:dp[i] = 1

class Solution {
public int lengthOfLIS(int[] nums) {
int len = nums.length; // dp[i] 表示以当前字符结尾的字符串中最长递增子序列的长度
int[] dp = new int[len]; int maxLen = 0;
for (int i = 0; i < len; i++) {
//base case
dp[i] = 1; for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
} maxLen = Math.max(maxLen, dp[i]);
} return maxLen;
}
}

301. 删除无效的括号

思路:回溯法


class Solution {
public List<String> removeInvalidParentheses(String s) {
// 左括号和右括号最少需要移除的个数
int leftRemove = 0, rightRemove = 0; for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
leftRemove++;
} else if (s.charAt(i) == ')') {
//存在左括号则消去一个
if (leftRemove > 0) {
leftRemove--;
} else if (leftRemove == 0) {
rightRemove++;
}
}
} StringBuilder track = new StringBuilder();
dfs(s, 0, track, 0, 0, leftRemove, rightRemove);
return new ArrayList<>(res);
} private Set<String> res = new HashSet<>(); private void dfs(String s, int index, StringBuilder track, int leftCnt, int rightCnt, int leftRemove, int rightRemove) {
if (s.length() == index) {
if (leftRemove == 0 && rightRemove == 0) {
res.add(track.toString());
} return;
} char ch = s.charAt(index); // 选择1:删除当前字符
if (ch == '(' && leftRemove > 0) {
dfs(s, index + 1, track, leftCnt, rightCnt, leftRemove - 1, rightRemove);
} else if (ch == ')' && rightRemove > 0) {
dfs(s, index + 1, track, leftCnt, rightCnt, leftRemove, rightRemove - 1);
} // 选择2:保留当前字符
track.append(ch);
if (ch == '(' ) {
dfs(s, index + 1, track, leftCnt + 1, rightCnt, leftRemove, rightRemove);
} else if (ch == ')' && leftCnt > rightCnt) {
dfs(s, index + 1, track, leftCnt, rightCnt + 1, leftRemove, rightRemove);
} else if (ch != '(' && ch != ')') {
dfs(s, index + 1, track, leftCnt, rightCnt, leftRemove, rightRemove);
}
track.deleteCharAt(track.length() - 1);
}
}

推荐题解:删除无效的括号

309. 最佳买卖股票时机含冷冻期

思路:动态规划

class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][] dp = new int[len][2]; dp[0][0] = 0;
dp[0][1] = -prices[0]; for (int i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], (i >= 2 ? dp[i - 2][0] : 0) - prices[i]);
} return dp[len - 1][0];
}
}

312. 戳气球

思路:动态规划。推荐题解:[这个菜谱, 自己在家也能做] 关键思路解释

class Solution {
public int maxCoins(int[] nums) {
int len = nums.length;
// 前后两位各插入1
int[] newNums = new int[len + 2];
newNums[0] = 1;
newNums[len + 1] = 1;
for (int i = 0; i < len; i++) {
newNums[i + 1] = nums[i];
} //dp[i][j] 代表 戳爆开区间 (i, j) 中的气球所能取得的最大值
//默认值都为0,base case: dp[i][j] = 0, j - i < 3
int[][] dp = new int[len + 2][len + 2]; for (int size = 3; size <= len + 2; size++) {
//开区间起始位置
for (int start = 0; start <= len + 2 - size; start++) {
int max = 0;
//列举最后一个被戳爆的气球为 newNums[k]的所有情况, K属于[start + 1, start + size - 1),找到最大值
for (int k = start + 1; k < start + size - 1; k++) {
max = Math.max(max, dp[start][k] + dp[k][start + size - 1] + newNums[start] * newNums[k] * newNums[start + size - 1]);
}
dp[start][start + size - 1] = max;
}
} return dp[0][len + 1];
}
}

322. 零钱兑换

思路:动态规划。

class Solution {
public int coinChange(int[] coins, int amount) {
//状态:dp[i] 表示凑够i需要的最少硬币数
int[] dp = new int[amount + 1];
//求最小值,先初始为足够大。(若能凑成,最多需要amount枚硬币)
Arrays.fill(dp, amount + 1); //base case
dp[0] = 0; for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
//当前背包(总金额)若能装下物品(硬币面额)
if (i >= coins[j]) {
dp[i] = Math.min(dp[i - coins[j]] + 1, dp[i]);
}
}
} return dp[amount] >= amount + 1 ? -1 : dp[amount];
}
}

🔥 LeetCode 热题 HOT 100(71-80)的更多相关文章

  1. LeetCode 热题 HOT 100(05,正则表达式匹配)

    LeetCode 热题 HOT 100(05,正则表达式匹配) 不够优秀,发量尚多,千锤百炼,方可成佛. 算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力 ...

  2. 🔥 LeetCode 热题 HOT 100(81-90)

    337. 打家劫舍 III 思路:后序遍历 + 动态规划 推荐题解:树形 dp 入门问题(理解「无后效性」和「后序遍历」) /** * Definition for a binary tree nod ...

  3. 🔥 LeetCode 热题 HOT 100(51-60)

    142. 环形链表 II 思路:快慢指针,快慢指针相遇后,慢指针回到头,快慢指针步伐一致一起移动,相遇点即为入环点 /** * Definition for singly-linked list. * ...

  4. 🔥 LeetCode 热题 HOT 100(31-40)

    75. 颜色分类 思路:将 2 往后放,0 往前放,剩余的1自然就放好了. 使用双指针:left.right 分别指向待插入的 0 和 2 的位置,初始 left 指向数组头,right 指向数组尾部 ...

  5. 🔥 LeetCode 热题 HOT 100(21-30)

    46. 全排列 思路:典型回溯法 class Solution { public List<List<Integer>> permute(int[] nums) { Linke ...

  6. 🔥 LeetCode 热题 HOT 100(61-70)

    207. 课程表 思路:根据题意可知:当课程之间不存在 环状 循环依赖时,便能完成所有课程的学习,反之则不能.因此可以将问题转换成: 判断有向图中是否存在环.使用 拓扑排序法 : 构建 入度表:记录每 ...

  7. 🔥 LeetCode 热题 HOT 100(41-50)

    102. 二叉树的层序遍历 思路:使用队列. /** * Definition for a binary tree node. * public class TreeNode { * int val; ...

  8. 🔥 LeetCode 热题 HOT 100(11-20)

    20. 有效的括号 class Solution { public boolean isValid(String s) { Map<Character, Character> map = ...

  9. 🔥 LeetCode 热题 HOT 100(1-10)

    1. 两数之和 思路一:暴力遍历所有组合 class Solution { public int[] twoSum(int[] nums, int target) { for (int i = 0; ...

随机推荐

  1. WEB安全新玩法 [3] 防护交易数据篡改

    在任何涉及交易的系统中,客户与商家之间的交易数据具有核心作用,如购买商品的价格.数量.型号和优惠券等.在客户挑选商品的过程中,这些交易数据逐渐形成:待客户提交订单时,交易数据被商家接收,形成双方认可的 ...

  2. 再试Hibernate框架

    几个月前因为学习需要第一次接触了Hibernate(之前一直在用MyBatis),后来觉得有点难,也急着找工作,所以就没继续学下去了.但是找工作的时候发现Hibernate的需求更高,使用率更高,所以 ...

  3. ANDROID开发之OOM:一张图片(BitMap)占用内存的计算 图片内存优化

    Android中一张图片(BitMap)占用的内存主要和以下几个因数有关:图片长度,图片宽度,单位像素占用的字节数. 一张图片(BitMap)占用的内存=图片长度*图片宽度*单位像素占用的字节数 注: ...

  4. 玩转STM32MP157-开发环境搭建

    (一)STM32MP 1.什么是 STM32MPU STM32MPU是 ST 推出的 Cortex-A7 + Cortex-M4 多核异构处理器 STM32MPU151 是单核 A7+M4,.STM3 ...

  5. ES6学习笔记之 let与const

    在js中,定义变量时要使用var操作符,但是var有许多的缺点,如:一个变量可以重复声明.没有块级作用域.不能限制修改等. //缺点1:变量可以重复声明 var a=1; var a=2; conso ...

  6. Windows10 准备/安装Flutter研发环境

    Flutter简介 Flutter 是 Google 开源的 UI 工具包,帮助开发者通过一套代码库高效构建多平台精美应用,支持移动.Web.桌面和嵌入式平台. Flutter 中国 安装Flutte ...

  7. 我是怎么写 Git Commit message 的?

    目录 作用 用的什么规范? type scope subject body footer 参考文章 用的什么辅助工具? 作用 编写格式化的 commit message 能够大大提高代码的维护效率. ...

  8. 19、lnmp_mysql、nfs组件分离

    19.1.LNMP一体机的数据库分离成独立的数据库: 1.根据以上学习过的方法在db01服务器上安装独立的mysql数据库软件: 2.在web01服务器上导出原先的数据库: [root@web01 t ...

  9. HDU 4292 Food 多源多汇入门题

    Food 有F种食物和D种饮料,每种食物或饮料只能供有限次,且每个人只享用一种食物和一种饮料.现在有n个人,每个人都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几个人同时享用到自己喜欢的食物和饮 ...

  10. AcWing 1303. 斐波那契前 n 项和

    输出斐波那契数列前 n 项和 对m取摸的结果 #include<bits/stdc++.h> #define LL long long #define N 3 using namespac ...