22 min to read
LeetCode Daily Code
Daily Code
2020.06.25
Problem
- 给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
- 拆分时可以重复使用字典中的单词。
- 你可以假设字典中没有重复的单词。
- 链接:https://leetcode-cn.com/problems/word-break
- 示例:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
输出: false
Solution
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int n = s.length();
// hold[i] 表示 s 中以 i - 1 结尾的字符串是否可被wordDict拆分
boolean[] hold = new boolean[n + 1];
hold[0] = true;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
if (hold[j] && wordDict.contains(s.substring(j, i))) {
hold[i] = true;
break;
}
}
}
return hold[n];
}
}
Get
- contains方法 返回布尔值
/* String s;
List<String> list = new ArrayList<String>(); */
s.contains("hello"); //检验s是否包含字串"hello"
list.contains("hello"); //检验list(集合)是否包含元素"hello"
2020.06.26
Problem
- 编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
说明:
输入:[1, 2, 3, 3, 2, 1]
输出:[1, 2, 3]
输入:[1, 1, 1, 1, 2]
输出:[1, 2]
Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeDuplicateNodes(ListNode head) {
List<Integer> list = new ArrayList<>();
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode hold = dummyHead;
if(head==null){
return head;
}
while(hold.next != null){
if(!list.contains(hold.next.val)){
list.add(hold.next.val);
hold = hold.next;
}
else{
hold.next = hold.next.next;
}
}
return dummyHead.next;
}
}
Get
- Java中的集合
集合名 | 线程安全 | 线程同步 | 元素重复 | 允许null | 存储有序 | 添加方法 |
---|---|---|---|---|---|---|
ArrayList | × | × | √ | √ | √ | add() |
LinkedList | × | × | √ | √ | √ | add() |
HashSet | × | × | × | × | × | add() |
HashMap | × | × | × | × | × | put() |
Hashtable | √ | √ | × | × | × | add() |
2020.06.27
Problem
- 给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
说明:
输入: [1,2,0]
输出: 3
输入: [7,8,9,11,12]
输出: 1
Solution
class Solution {
public int firstMissingPositive(int[] nums) {
if(nums.length == 0){
return 1;
}
var list = new ArrayList<Integer>();
int ans = 0;
for(int i = 0;i < nums.length;i++){
list.add(nums[i]);
}
//list.size()+2 可应对[1],[0,1,2...]等特殊数组
for(int i = 1;i<list.size() + 2;i++){
if(!list.contains(i)){
ans = i;
break;
}
}
return ans;
}
}
2020.06.29
Problem
- 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
说明:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
Solution
class Solution {
public int findKthLargest(int[] nums, int k) {
//调用库函数
if(nums.length == 0) return 0;
Arrays.sort(nums);
return nums[nums.length-k];
/* 手写某一种排序算法
var len = nums.length;
for (var i = 0; i < len - 1; i++) {
for (var j = 0; j < len - 1 - i; j++) {
if (nums[j] > nums[j+1]) { // 相邻元素两两对比
var temp = nums[j+1]; // 元素交换
nums[j+1] = nums[j];
nums[j] = temp;
}
}
}
return nums[len-k];
*/
}
}
Get
- 排序算法
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|
插入排序 | O(n2) | O(n2) | O(n) | O(1) | 稳定 |
希尔排序 | O(n1.3) | O(n2) | O(n) | O(1) | 不稳定 |
选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 |
冒泡排序 | O(n2) | O(n2) | O(n) | O(1) | 稳定 |
快速排序 | O(nlog2n) | O(n2) | O(nlog2n) | O(nlog2n) | 不稳定 |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 |
计数排序 | O(n+k) | O(n+k) | O(n+k) | O(n+k) | 稳定 |
桶排序 | O(n+k) | O(n2) | O(n) | O(n+k) | 稳定 |
基数排序 | O(n*k) | O(n*k) | O(n*k) | O(n+k) | 稳定 |
2020.07.03
Problem
- 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
说明:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
// 左右等分建立左右子树,中间节点作为子树根节点,递归该过程
return nums == null ? null : buildTree(nums, 0, nums.length - 1);
}
private TreeNode buildTree(int[] nums, int left, int right) {
if (left > right) {
return null;
}
int m = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[m]);
root.left = buildTree(nums, left, m - 1);
root.right = buildTree(nums, m + 1, right);
return root;
}
}
2020.07.04
Problem
- 给定一个只包含 ‘(‘ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
说明:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
Solution
class Solution {
public int longestValidParentheses(String s) {
char[] chars = s.toCharArray();
return Math.max(calc(chars, 0, 1, chars.length, '('), calc(chars, chars.length -1, -1, -1, ')'));
}
private static int calc(char[] chars , int i , int flag,int end, char cTem){
int max = 0, sum = 0, currLen = 0,validLen = 0;
for (;i != end; i += flag) {
sum += (chars[i] == cTem ? 1 : -1);
currLen ++;
if(sum < 0){
max = max > validLen ? max : validLen;
sum = 0;
currLen = 0;
validLen = 0;
}else if(sum == 0){
validLen = currLen;
}
}
return max > validLen ? max : validLen;
}
}
2020.07.05
Problem
- 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。
- ’?’ 可以匹配任何单个字符。’*’ 可以匹配任意字符串(包括空字符串)。
说明:
- s 可能为空,且只包含从 a-z 的小写字母。
- p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
- 链接:https://leetcode-cn.com/problems/wildcard-matching
- 示例:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
输入:
s = "aa"
p = "*"
输出: true
解释: '*' 可以匹配任意字符串。
输入:
s = "cb"
p = "?a"
输出: false
解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
Solution
class Solution {
public static boolean isMatch(String s, String p) {
int sn = s.length();
int pn = p.length();
boolean[][] dp = new boolean[sn + 1][pn + 1];
char[] sArray = s.toCharArray();
char[] pArray = p.toCharArray();
dp[0][0] = true;
for (int i = 1; i <= pn; ++i) {
if (pArray[i-1] == '*') {
dp[0][i] = true;
} else {
break;
}
}
for (int i = 1; i <= sn; ++i) {
for (int j = 1; j <= pn; ++j) {
if (pArray[j-1] == '*') {
dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
} else if (pArray[j-1] == '?' || sArray[i-1] == pArray[j-1]) {
dp[i][j] = dp[i - 1][j - 1];
}
}
}
return dp[sn][pn];
}
}
Get
- 动态规划
- 动态规划问题,大致可以通过以下四部进行解决。
- 划分状态,即划分子问题。
- 状态表示,即如何让计算机理解子问题。
- 状态转移,即父问题是如何由子问题推导出来的。
- 确定边界,确定初始状态是什么?最小的子问题?最终状态又是什么?
2020.07.06
Problem
- 一个机器人位于一个m x n 网格的左上角。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下。 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
说明:
- 链接:https://leetcode-cn.com/problems/unique-paths-ii
- m 和 n 的值均不超过 100。
- 网格中的障碍物和空位置分别用 1 和 0 来表示。
- 示例:
输入:
[
[0,0,0],
[0,1,0],
[0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
Solution
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
if (obstacleGrid[0][0] == 1) return 0;
int row = obstacleGrid.length;
int col = obstacleGrid[0].length;
int[][] dp = new int[row][col];
dp[0][0] = 1;
// base case
for (int i = 1; i < row; i ++) {
if (dp[i - 1][0] == 1 && obstacleGrid[i][0] != 1) dp[i][0] = 1;
else break;
}
for (int i = 1; i < col; i ++) {
if (dp[0][i - 1] == 1 && obstacleGrid[0][i] != 1) dp[0][i] = 1;
else break;
}
for (int i = 1; i < row; i ++) {
for (int j = 1; j < col; j ++) {
if (obstacleGrid[i][j] == 1) continue;
dp[i][j] = (obstacleGrid[i - 1][j] == 1 ? 0 : dp[i - 1][j])
+ (obstacleGrid[i][j - 1] == 1 ? 0 : dp[i][j - 1]);
}
}
return dp[row - 1][col - 1];
}
}
2020.07.07
Problem
- 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明:
- 链接:https://leetcode-cn.com/problems/path-sum
- 叶子节点是指没有子节点的节点。
- 示例:
给定如下二叉树,以及目标和 sum = 22
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
Solution
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null) {
return false;
}
if(root.left == null && root.right == null) {
return root.val == sum;
}
return hasPathSum(root.left, sum - root.val)
|| hasPathSum(root.right, sum - root.val);
}
}
2020.07.08
Problem
- 你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。
说明:
- 链接:https://leetcode-cn.com/problems/diving-board-lcci
- 返回的长度需要从小到大排列。
- 示例:
输入:
shorter = 1
longer = 2
k = 3
输出: {3,4,5,6}
Solution
class Solution {
public int[] divingBoard(int shorter, int longer, int k) {
if(k == 0) {
return new int[]{}; // 表示返回集合 {} 空集
}
if (longer == shorter) {
return new int[]{k * longer}; // 表示返回集合 {value} value为k*longer的值
}
int n = longer - shorter;
int[] ans = new int[k + 1];
for(int i = 0;i <= k;i++) {
ans[i] = shorter * k + i * n;
}
return ans;
}
}
Get
- return new int[]{}; // 表示返回集合 {} ,空集。
- return new int[]{k * longer}; // 表示返回集合 {value} ,value为k * longer的值。
2020.07.12
Problem
- 一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由M x N 个房间组成的二维网格。
- 英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
- 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
- 有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
- 为了尽快到达公主,骑士决定每次只向右或向下移动一步。
- 编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
说明:
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2(K) -3 3
-5 -10 1
10 30 -5(P)
Solution
class Solution {
public int calculateMinimumHP(int[][] dungeon) {
int row = dungeon.length;
int col = dungeon[0].length;
int[][] dp = new int[row][col];
for(int i = row - 1; i >= 0; i--){
for(int j = col - 1; j >= 0; j--){
if(i==row-1&&j==col-1){ //终点的情况
dp[i][j]=Math.max(1, 1-dungeon[i][j]);
}else if(i==row-1){ //最后一行的情况
dp[i][j]=Math.max(1, dp[i][j+1]-dungeon[i][j]);
}else if(j==col-1){ //最后一列的情况
dp[i][j]=Math.max(1, dp[i+1][j]-dungeon[i][j]);
}else{
dp[i][j]=Math.max(1, Math.min(dp[i+1][j],dp[i][j+1])-dungeon[i][j]);
}
}
}
return dp[0][0];
}
}
2020.07.20
Problem
- 给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1必须小于index2。
说明:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
Solution
class Solution {
public int[] twoSum(int[] numbers, int target){
int len = numbers.length;
int left = 0, right = len - 1;
while(left < right){
int sum = numbers[left] + numbers[right];
if(sum == target){
return new int[]{left + 1, right + 1};
}else if(sum > target){
right--;
}else {
left++;
}
}
return new int[2];
}
}
Comments