🔥 LeetCode 热题 HOT 100(71-80)
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 < i
且 nums[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)的更多相关文章
- LeetCode 热题 HOT 100(05,正则表达式匹配)
LeetCode 热题 HOT 100(05,正则表达式匹配) 不够优秀,发量尚多,千锤百炼,方可成佛. 算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力 ...
- 🔥 LeetCode 热题 HOT 100(81-90)
337. 打家劫舍 III 思路:后序遍历 + 动态规划 推荐题解:树形 dp 入门问题(理解「无后效性」和「后序遍历」) /** * Definition for a binary tree nod ...
- 🔥 LeetCode 热题 HOT 100(51-60)
142. 环形链表 II 思路:快慢指针,快慢指针相遇后,慢指针回到头,快慢指针步伐一致一起移动,相遇点即为入环点 /** * Definition for singly-linked list. * ...
- 🔥 LeetCode 热题 HOT 100(31-40)
75. 颜色分类 思路:将 2 往后放,0 往前放,剩余的1自然就放好了. 使用双指针:left.right 分别指向待插入的 0 和 2 的位置,初始 left 指向数组头,right 指向数组尾部 ...
- 🔥 LeetCode 热题 HOT 100(21-30)
46. 全排列 思路:典型回溯法 class Solution { public List<List<Integer>> permute(int[] nums) { Linke ...
- 🔥 LeetCode 热题 HOT 100(61-70)
207. 课程表 思路:根据题意可知:当课程之间不存在 环状 循环依赖时,便能完成所有课程的学习,反之则不能.因此可以将问题转换成: 判断有向图中是否存在环.使用 拓扑排序法 : 构建 入度表:记录每 ...
- 🔥 LeetCode 热题 HOT 100(41-50)
102. 二叉树的层序遍历 思路:使用队列. /** * Definition for a binary tree node. * public class TreeNode { * int val; ...
- 🔥 LeetCode 热题 HOT 100(11-20)
20. 有效的括号 class Solution { public boolean isValid(String s) { Map<Character, Character> map = ...
- 🔥 LeetCode 热题 HOT 100(1-10)
1. 两数之和 思路一:暴力遍历所有组合 class Solution { public int[] twoSum(int[] nums, int target) { for (int i = 0; ...
随机推荐
- 【模拟7.27】单(liu_runda学长的神题)
好像用到一些高中数学知识...... 满分做法: case 0:已知a数组求b数组 因为是树状结构,设当前节点x 儿子to 我们从任意一点出发可求出b[root]来,之后我们可以通过寻找两两相连节点的 ...
- 【题解】入阵曲 luogu3941 前缀和 压维
丹青千秋酿,一醉解愁肠. 无悔少年枉,只愿壮志狂 题目 题目描述 小 F 很喜欢数学,但是到了高中以后数学总是考不好. 有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识算法竞赛的 时 ...
- 在js中使用moment将秒转换为多少天多少小时多少分多少秒
let x = 2703750;//单位是秒 var d = moment.duration(x, 'seconds'); console.log(Math.floor(d.asDays()) + ' ...
- 温故知新,.Net Core遇见Consul(HashiCorp),实践分布式服务注册与发现
什么是Consul 参考 https://www.consul.io https://www.hashicorp.com 使用Consul做服务发现的若干姿势 ASP.NET Core 发布之后通过命 ...
- 美化terminal时碰到的问题- Set-Theme
报错: 1 Set-Theme Set-Theme: The term 'Set-Theme' is not recognized as a name of a cmdlet, function, s ...
- 28、python3.7(windows)将ORACLE11gR2中的数据取出写入excel表
28.1.下载python的离线扩展模块: 1.windows下python的离线扩展模块下载地址为: https://www.lfd.uci.edu/~gohlke/pythonlibs/ 提示: ...
- 8、ITSM基本概念(2)
6.流程和职能: 7.故障管理: (1)故障管理的输入和输出: (2)故障管理的目标: 优先解决影响度大的事件: (3)故障管理的指标: (4)故障管理的流程: 8.问题管理: (1)问题管理的输入和 ...
- CRM系统什么时候需要使用
CRM客户关系管理系统,相信每个人都会有所了解.现如今随着企业的发展需求,CRM软件已经成为了企业管理的刚需.无论是何种行业和规模的企业,客户都是最重要的资源,提高客户满意度也是企业的首要任务.如果您 ...
- linux 退出状态码
状态码 描述 0 命令成功结束 1 一般性未知错误 2 不适合的shell 命令 123 命令不可执行 127 没找到命令 128 无效退出参数 128+x 与linux信号x相关的严重错误 130 ...
- linux安装subversion
原文: https://www.cnblogs.com/liuxianan/p/linux_install_svn_server.html 安装 使用yum安装非常简单: yum install su ...