完整教程:leetcode (2)

news/2025/9/26 8:27:57/文章来源:https://www.cnblogs.com/slgkaifa/p/19112444

完整教程:leetcode (2)

Leetcode 2

  • 51. N-Queens
  • 53. Maximum Subarray
  • 54. Spiral Matrix
  • 55. Jump Game
  • 56. Merge Intervals
  • 57. Insert Interval
  • 58. Length of Last Word
  • 59. Spiral Matrix II
  • 61. Rotate List
  • 62. Unique Paths
  • 63. Unique Paths II
  • 64. Minimum Path Sum
  • 66. Plus One
  • 67. Add Binary
  • 69. Sqrt(x)
  • 70. Climbing Stairs
  • 71. Simplify Path
  • 72. Edit Distance
  • 73. Set Matrix Zeroes
  • 74. Search a 2D Matrix
  • 75. Sort Colors
  • 76. Minimum Window Substring
  • 77. Combinations
  • 78. Subsets
  • 79. Word Search
  • 80. Remove Duplicates from Sorted Array II
  • 81. Search in Rotated Sorted Array II
  • 82. Remove Duplicates from Sorted List II
  • 83. Remove Duplicates from Sorted List
  • 86. Partition List
  • 88. Merge Sorted Array
  • 89. Gray Code
  • 90. Subsets II
  • 91. Decode Ways
  • 92. Reverse Linked List II
  • 93. Restore IP Addresses
  • 94. Binary Tree Inorder Traversal
  • 95. Unique Binary Search Trees II
  • 96. Unique Binary Search Trees
  • 97. Interleaving String
  • 98. Validate Binary Search Tree
  • 99. Recover Binary Search Tree
  • 100. Same Tree

51. N-Queens

https://leetcode.com/problems/n-queens/description/

The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.
Given an integer n, return all distinct solutions to the n-queens puzzle. You may return the answer in any order.
Each solution contains a distinct board configuration of the n-queens’ placement, where ‘Q’ and ‘.’ both indicate a queen and an empty space, respectively.

Example 1:
Input: n = 4
Output: [[“.Q…”,“…Q”,“Q…”,“…Q.”],[“…Q.”,“Q…”,“…Q”,“.Q…”]]
Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
Example 2:
Input: n = 1
Output: [[“Q”]]

Constraints:
1 <= n <= 9

return all distinct solutions to the n-queens puzzle.
Generate all solutions backtracking
validate every row col diagonal only have one queen

function dfs(node, state):
if state is a solution:
report(state) # e.g. add state to final result list
return
for child in children:
if child is a part of a potential solution:
state.add(child) # make move
dfs(child, state)
state.remove(child) # backtrack

Don’t validate at the end when put into result list
Validate before, when add from the available list, only add the correct item

if child is a part of a potential solution:
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择

for (int col = 0; col < board.length; col++) {
if (isValid(board, row, col)) {
board[row][col] = 'Q';
backtrack(solutions, board, row + 1);
board[row][col] = '.';
// Backtrack, remove the queen and try another position
}
}

Permutation

for(type i: arr)
if set.contains(i) continue;
set.add();
backtracking()
set.remove();

检查右上方: for (int i = row - 1, j = col + 1; i >= 0 && j < chess.length; i–, j++)
检查左上方: for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i–, j–)

class Solution
{
public List<
List<
String>
> solveNQueens(int n) {
List<
List<
String>
> resultList = new ArrayList<
>();
//each availble solution is n row n col [n][n]
char[][] chess = new char[n][n];
for (int i = 0; i < n; i++) {
Arrays.fill(chess[i], '.');
//Arrays.fill() for one dimension array
}
backtracking(resultList,chess,0);
return resultList;
}
private void backtracking(List<
List<
String>
> resultList, char[][] chess,int row){
int size = chess.length;
if(row == size){
resultList.add(toList(chess));
return;
}
for(int i = 0; i < size; i++){
if(isValid(chess,row,i)){
chess[row][i] = 'Q';
backtracking(resultList,chess,row+1);
chess[row][i] = '.';
}
}
}
private boolean isValid(char[][] chess, int row, int col) {
// Check column
for (int i = 0; i < row; i++) {
if (chess[i][col] == 'Q') {
return false;
}
}
// Check the diagonal from top-left to bottom-right
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (chess[i][j] == 'Q') {
return false;
}
}
// Check the diagonal from top-right to bottom-left 
for (int i = row - 1, j = col + 1; i >= 0 && j < chess.length; i--, j++) {
if (chess[i][j] == 'Q') {
return false;
}
}
return true;
}
private List<
String> toList(char[][] chess){
List<
String> path = new ArrayList<
>();
for (int i = 0; i < chess.length; i++) {
path.add(new String(chess[i]));
}
return path;
}
}

涉及全排列 时间复杂度 时间复杂度: O(N!)
空间复杂度: O(N^2)

时间复杂度 (Time Complexity):

最坏情况下的时间复杂度为 O(N!),因为你在每一行选择一个位置(最多 N 个选择),然后递归地选择下一行。

空间复杂度 (Space Complexity):

主存储: 主要由递归调用栈的深度决定,最大递归深度是 N,因此空间复杂度为 O(N)。
附加存储: 用于存储棋盘状态的二维数组 char[][] board 以及存储所有可能解的 List<List> solutions。棋盘的空间复杂度是 O(N^2 ),存储结果的列表的复杂度取决于解决方案的数量。

53. Maximum Subarray

53. Maximum Subarray

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
A subarray is a contiguous part of an array.

Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

brute force generate all the subarray

DP
数组值 范围 确定 long 还是int
特殊情况 全为负数
数组长度 空数组

when we start a new subarray? When the current sum is negative. But we need to store the negative answer before.

Input: [ -1 ]

class Solution
{
public int maxSubArray(int[] nums) {
int n = nums.length;
int max = Integer.MIN_VALUE, sum = 0;
for(int i=0; i<n; i++){
sum += nums[i];
max = Math.max(sum,max);
if(sum <
0) sum = 0;
}
return max;
}
}

只要sum>0,sum就能继续叠加
全负数组,选最大的负数/sum归零,判断当前位置是否是最大/比之前记录大

Wrong:
遍历,统计和,永远取最大值

  • currentSum = Math.max(currentSum + arr[i], arr[i])
  • maxSum = Math.max(currentSum, maxSum)
    对于当前数,只有两种可能,加入(currentSum + arr[i])或者不加入(arr[i],从当前数开始计数),因为不限制长度,总是取截止到当前长度最大的可能性

get the sum of the current point

  1. add nums[i] to the solution
  2. or start a new subarray

current_sum = max(current_sum + nums[i], current_sum)

and decide whether to update solution / max.

//wrong ignore negative
class Solution
{
public int maxSubArray(int[] nums) {
int n = nums.length;
int max = Integer.MIN_VALUE, current_sum = 0;
for(int i=0; i<n; i++){
current_sum = Math.max(current_sum + nums[i], current_sum) ;
max = Math.max(current_sum,max);
}
return max;
}
}

54. Spiral Matrix

54. Spiral Matrix

Given an m x n matrix, return all elements of the matrix in spiral order.
在这里插入图片描述
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [1,2,3,6,9,8,7,4,5]

Traverse the row from the beginning to the end, turn to the column. Travese the row from end to the begin. Go to the column.

Shift the direction when hitting the boundary.
Update the boundary at the same time.
(x,y) : coordinate
up down right left : represent the boundary

class Solution
{
public List<
Integer> spiralOrder(int[][] matrix) {
//x up down y right left
List<
Integer> ansList = new ArrayList<
> ();
int num = matrix.length * matrix[0].length;
int n = 0;
int x = 0,y = 0;
int left = 0,right = matrix[0].length-1,up = 0, down = matrix.length-1;
while(n < num){
for(x = up,y = left; y<=right; y++){
if(n>=num) return ansList;
ansList.add(matrix[x][y]);
n++;
}
//y--;
up++;
for(x = up,y = right; x<=down; x++){
if(n>=num) return ansList;
ansList.add(matrix[x][y]);
n++;
}
right--;
for(x = down,y = right; y>=left; y--){
if(n>=num) return ansList;
ansList.add(matrix[x][y]);
n++;
}
down--;
for(x = down,y = left; x>=up; x--){
if(n>=num) return ansList;
ansList.add(matrix[x][y]);
n++;
}
left++;
}
return ansList;
}
}

55. Jump Game

55. Jump Game

You are given an integer array nums. You are initially positioned at the array’s first index, and each element in the array represents your maximum jump length at that position.
Return true if you can reach the last index, or false otherwise.

Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Calculate the max reachable range. as we only care about the last index, we can only calculate the max reachable index.
DP
Max reachable index = Max(max reachable index, current index + nums[current index])

public boolean canJump(int[] nums) {
//for an index to be reachable, each of the previous indices have to be reachable.
int reachable = 0;
for (int i=0; i<nums.length;
++i) {
if (i > reachable) return false;
reachable = Math.max(reachable, i + nums[i]);
}
return true;
}

2ms 90.47% 42.6MB 90.40%

traverse backward
2 <- 3 <- 1 <- 1 <- 4
Keep tracking backward and see if we can get to the start point.

public boolean canJump(int[] nums) {
int lastGoodIndexPosition = nums.length - 1;
for(int i = nums.length - 1; i >= 0; i--){
if(i + nums[i] >= lastGoodIndexPosition){
lastGoodIndexPosition = i;
}
}
return lastGoodIndexPosition == 0;
}

1ms 100% 42.8MB 89.55%

56. Merge Intervals

56. Merge Intervals

Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.

Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlap, merge them into [1,6].

Sort all the intervals by the start. All the intervals are non-overlapping when each start is bigger than the last end.
|_| | __ | |__|
Check every interval. If new start is no bigger than the current end, merge the interval, updating the current end and keep traversing.

class Solution
{
public int[][] merge(int[][] intervals) {
//sort first
//ans no defined size List .toArray(new int[x][])
List<
int[]> ans = new ArrayList<
>();
Arrays.sort(intervals, (a, b) ->
(a[0] - b[0]));
// intial range 
int start = intervals[0][0];
int end = intervals[0][1];
int i = 1;
while(i < intervals.length){
if(intervals[i][0] <= end) {
// If new start is no bigger than the current end
// merge these two intervals by updating the end
end = Math.max(end,intervals[i][1]);
}
else{
// they are independent, then insert prev interval into list
ans.add(new int[]{start,end
});
// update the current range 
start = intervals[i][0];
end = intervals[i][1];
}
i++;
}
// no interval left to check, add the current answer
ans.add(new int[] {start,end
});
return ans.toArray(new int[ans.size()][]);
}
}
  • sort

Arrays.sort()Default Ascending

Descending order:

Arrays.sort(num,new Comparator<
Integer>(){
public int compare(Integer a, Integer b){
return b-a;
}
});

lambda expressions:

Arrays.sort(intervals, (a, b) ->
(a[0] - b[0]));

Descending order:

Arrays.sort(nums, ( Integer a, Integer b) ->
{
return b-a;
});

String arrays, sorted by length:

Arrays.sort(strs, (String first, String second) ->
{
if(first.length() < second.length()) return -1;
else if(first.length() > second.length()) return 1;
else return 0;
});
ans.add(new int[] {start,end
});
  • arrayList.toArray()
ans.toArray(new int[ans.size()][]);

57. Insert Interval

57. Insert Interval

You are given an array of non-overlapping intervals intervals where intervals[i] = [starti, endi] represent the start and the end of the ith interval and intervals is sorted in ascending order by starti. You are also given an interval newInterval = [start, end] that represents the start and end of another interval.
Insert newInterval into intervals such that intervals is still sorted in ascending order by starti and intervals still does not have any overlapping intervals (merge overlapping intervals if necessary).
Return intervals after the insertion.

Example :

Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]

Constraints:
0 <= intervals.length <= 104
intervals[i].length == 2
0 <= starti <= endi <= 105
intervals is sorted by starti in ascending order.
newInterval.length == 2
0 <= start <= end <= 105

class Solution
{
public int[][] insert(int[][] intervals, int[] newInterval) {
int[][] addlist = new int[intervals.length+1][2];
List<
int[]> ans = new ArrayList<
>();
int i,j;
for(i = 0; i<intervals.length; i++){
addlist[i][0] = intervals[i][0];
addlist[i][1] = intervals[i][1];
}
addlist[i][0] = newInterval[0];
addlist[i][1] = newInterval[1];
Arrays.sort(addlist,(a,b)->
(a[0]-b[0]));
int begin = addlist[0][0];
int end = addlist[0][1];
for(i = 1; i < addlist.length; i++){
if(addlist[i][0]<=end){
end = Math.max(addlist[i][1],end);
}
else{
ans.add(new int[] {begin,end
});
begin = addlist[i][0];
end = addlist[i][1];
}
}
ans.add(new int[] {begin,end
});
return ans.toArray(new int[ans.size()][]);
}
}

找合适的位置插入,更新当前区间,继续遍历,查看剩余区间是否需要更新。

58. Length of Last Word

58. Length of Last Word

Given a string s consisting of words and spaces, return the length of the last word in the string.
A word is a maximal substring consisting of non-space characters only.

Example:

Input: s = " fly me to the moon "
Output: 4
Explanation: The last word is “moon” with length 4.

Constraints:

1 <= s.length <= 104
s consists of only English letters and spaces ’ '.
There will be at least one word in s.

traverse backward and skip the space

public int lengthOfLastWord(String s) {
int count = 0;
int end = s.length()-1;
while(s.charAt(end)==' '){
end--;
}
while(end >= 0 && s.charAt(end)!=' '){
count++;
end--;
}
return count;
}
class Solution
{
public int lengthOfLastWord(String s) {
int begin = 0;
int end = s.length()-1;
while(s.charAt(end)==' '){
end--;
}
if(s.charAt(end)!=' '){
begin = end;
}
while(begin>=0 && s.charAt(begin)!=' '){
begin--;
}
return end-begin;
}
}

59. Spiral Matrix II

59. Spiral Matrix II

Given a positive integer n, generate an n x n matrix filled with elements from 1 to n2 in spiral order.

Example:

在这里插入图片描述

Input: n = 3
Output: [[1,2,3],[8,9,4],[7,6,5]]

Constraints:

1 <= n <= 20

Search in a matrix and Use visited array
Use array to store direction.

int [][] directions = {
{
0,1
},{
1,0
},{
0,-1
},{
-1,0
}
};
x += direction[0];
y += direction[1];

Use visited array to mark if visited.

boolean[][] visited = new boolean[n][n];

Use boundary check

if(x>=0 && x<leftBoundary &
& y>=0 && y<bottomBoundary)
class Solution
{
public int[][] generateMatrix(int n) {
//go right, then down, then left, and then up..repeat
int [][] directions = {
{
0,1
},{
1,0
},{
0,-1
},{
-1,0
}
};
boolean[][] visited = new boolean[n][n];
int [][] ans = new int[n][n];
int count = 1;
int visitCount = 0;
int x=0;
int y=-1;
int sum = n * n;
while(visitCount != sum){
for(int[] direction : directions){
while(isValid(ans, x+direction[0], y+direction[1]) &&
!visited[x+direction[0]][y+direction[1]]){
x += direction[0];
y += direction[1];
ans[x][y] = count++;
visited[x][y] = true;
visitCount++;
}
}
}
return ans;
}
public boolean isValid(int[][] ans, int x, int y){
return (x>=0 && x<ans.length &
& y>=0 && y<ans[0].length);
}
}

Turn the direction and Update the boundary
the same as NO.54 Spiral Matrix

public int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
int top = 0,bottom = n-1,left = 0,right = n-1;
int num = 1;
while(left<=right && top <=bottom){
for(int i=left; i<=right; i++){
result[top][i] = num++;
}
top++;
for(int i= top; i<=bottom; i++){
result[i][right] = num++;
}
right--;
for(int i= right; i>=left; i-- ){
result[bottom][i] = num++;
}
bottom--;
for(int i = bottom; i>=top; i--){
result[i][left] = num++;
}
left++;
}
return result;
}

61. Rotate List

61. Rotate List

Given the head of a linked list, rotate the list to the right by k places.

Input: head = [1,2,3,4,5], k = 2
Output: [4,5,1,2,3]
在这里插入图片描述

dummy head -> original head -> k -> after k
dummy head -> k -> after k -> original head

There are k nodes after k (len - k%len th node from head)
Break the linkedlist at k (node 2 -> node 3).
Swap the order, make the last k nodes to the beginning of the linkedlist.

Travese the linked list to get the list length.
pos = len - k%len;

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution
{
public ListNode rotateRight(ListNode head, int k) {
if(head == null) return head;
if(head.next ==null) return head;
int len = 0;
ListNode dummyHead = new ListNode() {
};
dummyHead.next = head;
ListNode p, s = dummyHead;
while(s.next!=null){
len++;
s = s.next;
}// make s point to the last node
if(k%len == 0) return head;
int pos = len - k%len;
p = head;
while(pos >
1){
p = p.next;
pos--;
}// find the k position, make p point to the previous node of k position
dummyHead.next = p.next;
s.next = head;
p.next = null;
return dummyHead.next;
}
}

62. Unique Paths

There is a robot on an m x n grid. The robot is initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]). The robot can only move either down or right at any point in time.
Given the two integers m and n, return the number of possible unique paths that the robot can take to reach the bottom-right corner.
The test cases are generated so that the answer will be less than or equal to 2 * 109.

在这里插入图片描述

Input: m = 3, n = 7
Output: 28

  • We only have one way to go to (x , 0), going right. One way to go to (0, y), going down.
    • x == 0 || y == 0, path[ x ][ y ] = 1
  • Of any other (x, y), the possible path is equal to path of (x-1, y) add path of (x, y-1).
    • path[ x ][ y ] = path[ x - 1 ][ y ] + path[ x ][ y - 1 ]

Recursion

Time Limit Exceeded

private int move(int x, int y,int m, int n){
if(x==m && y==n){
return 1;
}
if(x>m || y>n) return 0;
return move(x+1,y,m,n)+move(x,y+1,m,n);
}

Use array to store the possible outcomes.
In java, arrays are objects. It’s “pass-by-reference”.

if(note[x-1][y]==0) -> (x-1,y) is unvisited
from the end ((m-1,n-1) ?) to the beginning ((0,0) 1).

class Solution
{
public int uniquePaths(int m, int n) {
int[][] note = new int[m][n];
return move(m-1,n-1,note);
//return note[m-1][n-1];
}
private int move(int x, int y,int[][] note){
if(x==0 || y==0){
return 1;
}
//can only move either down or right 
if(note[x-1][y]==0) note[x-1][y] = move(x-1,y,note);
if(note[x][y-1]==0) note[x][y-1] = move(x,y-1,note);
note[x][y] = note[x-1][y] + note[x][y-1];
return note[x][y];
}
}

Dynamic Programming

From the beginning to the end, note[i][j] = note[i-1][j] + note[i][j-1]

class Solution
{
public int uniquePaths(int m, int n) {
int[][] note = new int[m][n];
for(int i = 0; i < m; i++){
note[i][0] = 1;
}
for(int i = 0; i < n; i++){
note[0][i] = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
note[i][j] = note[i-1][j] + note[i][j-1];
}
}
return note[m-1][n-1];
}
}

63. Unique Paths II

63. Unique Paths II

You are given an m x n integer array grid. There is a robot initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m-1][n-1]). The robot can only move either down or right at any point in time.
An obstacle and space are marked as 1 or 0 respectively in grid. A path that the robot takes cannot include any square that is an obstacle.
Return the number of possible unique paths that the robot can take to reach the bottom-right corner.
The testcases are generated so that the answer will be less than or equal to 2 * 109.

Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid.
There are two ways to reach the bottom-right corner:
1 Right -> Right -> Down -> Down
2 Down -> Down -> Right -> Right

Recursion

class Solution
{
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int[][] note = new int[obstacleGrid.length][obstacleGrid[0].length];
for(int i = 0; i < obstacleGrid.length; i++)
for(int j = 0; j < obstacleGrid[0].length; j++)
note[i][j] = -1;
move(obstacleGrid,obstacleGrid.length-1,obstacleGrid[0].length-1,note);
return note[note.length-1][note[0].length-1];
}
private void move(int[][] obstacleGrid,int x,int y,int[][] note){
if(obstacleGrid[x][y]==1){
//is obstacleGrid 0 road
note[x][y] = 0;
return ;
}
if(x==0 && y==0){
//start point
note[x][y] = 1;
return ;
}
//note[][]==-1 unvisited 
if(x-1>=0 && y>=0 && note[x-1][y]==-1) move(obstacleGrid,x-1,y,note);
if(x>=0 && y-1>=0 && note[x][y-1]==-1) move(obstacleGrid,x,y-1,note);
if(y==0){
//the top line
note[x][y] = note[x-1][y];
return ;
}
if(x==0){
//the left line
note[x][y] = note[x][y-1];
return ;
}
note[x][y] = note[x-1][y] + note[x][y-1];
return ;
}
}

DP

class Solution
{
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] note = new int[m][n];
for(int x = 0; x < m; x++)
for(int y = 0; y < n; y++){
if(obstacleGrid[x][y]==1){
//is obstacleGrid 0 road
note[x][y] = 0;
}
else if(x==0 && y==0){
note[x][y] = 1;
}
else if(x-1>=0 && y==0){
//on the top line
note[x][y] = note[x-1][y];
}
else if(y-1>=0 && x==0){
//on the left line
note[x][y] = note[x][y-1];
}
else{
note[x][y] = note[x-1][y] + note[x][y-1];
}
}
return note[m-1][n-1];
}
}

64. Minimum Path Sum

64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right, which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.

在这里插入图片描述
Input: grid = [[1,3,1],[1,5,1],[4,2,1]]
Output: 7
Explanation: Because the path 1 → 3 → 1 → 1 → 1 minimizes the sum.

DP

There is only two choices when choosing the road. One grid can be only reached either by the up grid or the left grid.

class Solution
{
public int minPathSum(int[][] grid) {
int i,j;
int[][] dp = new int[grid.length][grid[0].length];
for(i = 0; i < grid.length; i++){
for(j = 0; j < grid[0].length; j++){
if(i==0 && j==0){
dp[i][j] = grid[i][j];
continue;
}
if(i==0){
dp[i][j] = dp[i][j-1] + grid[i][j];
}
else if(j==0){
dp[i][j] = dp[i-1][j] + grid[i][j];
}
else if(i-1>=0 && j-1>=0){
dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
}
return dp[grid.length-1][grid[0].length-1];
}
}

66. Plus One

66. Plus One

You are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading 0’s.
Increment the large integer by one and return the resulting array of digits.

Input: digits = [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.
Incrementing by one gives 123 + 1 = 124.
Thus, the result should be [1,2,4].

Method 1
Initate the carry = 1to represent add 1 at the least significant digit.

class Solution
{
public int[] plusOne(int[] digits) {
int i = digits.length;
int [] ans = new int[digits.length+1];
ans[i]=digits[i-1] +1;
int carry = 1;
while(i>
0){
if(carry==1){
ans[i]=digits[i-1] + 1;
if(ans[i]>=10){
carry = 1;
ans[i] %= 10;
}else{
carry = 0;
// break;
}
}
else if(carry==0){
//don't have carry, copy
ans[i]=digits[i-1];
}
i--;
}
if(i==0 && carry==1){
//the new number is 1 digit longer
ans[0]=1;
}
if(ans[0]==0){
//two numbers have the same length
for(i=1;i<=digits.length;i++){
digits[i-1] = ans[i];
}
return digits;
}
return ans;
}
}

Method 2
Loop backward.
When the current digit is 9, we should have a carry 1. Or we should add 1 to the current digit and stop.
When all the digits are 9, the new number is 1 digit longer. 1 0000.

public int[] plusOne(int[] digits) {
int n = digits.length;
for(int i = n -1; i >= 0; i--){
if(digits[i] == 9){
digits[i] = 0;
}
else{
digits[i]++;
return digits;
}
}
//the new number is 1 digit longer
int[] new_digits = new int[n+1];
new_digits[0] = 1;
return new_digits;
}

67. Add Binary

67. Add Binary

Given two binary strings a and b, return their sum as a binary string.

Input: a = “11”, b = “1”
Output: “100”

Use StringBuilder instead of String when representing a mutable string.
Binary addition: Add from the less significant digit. Carry 1 into the next digit when the sum of two digits is greater than 1.

class Solution
{
public String addBinary(String a, String b) {
StringBuilder ans = new StringBuilder();
int sum;
int i = a.length()-1;
int j = b.length()-1;
int carry = 0;
while(i>=0 && j>=0){
sum = a.charAt(i) -'0' + b.charAt(j) -'0' + carry;
if(sum == 3){
carry = 1;
ans.append('1');
}else if(sum == 2 ){
carry =1;
ans.append('0');
}
else{
carry = 0;
ans.append(sum);
}
i--;
j--;
}
//Two Strings have different lengths. One still remain. And there could be carry left.
//Swap the remain string. Reduce duplicate code
if(j>=0){
a = b;
i = j;
}
while(i>=0){
sum = a.charAt(i) -'0' + carry;
if(sum == 3){
carry = 1;
ans.append('1');
}else if(sum == 2 ){
carry =1;
ans.append('0');
}
else{
carry = 0;
ans.append(sum);
}
i--;
}
if(carry ==1){
ans.append('1');
}
return ans.reverse().toString();
}
}

carry (0 / 1) = sum / 2;
remain (0 / 1) = sum % 2;

N carry = sum/N; remain = sum%N
Remember to check the carry at last.

while(i >= 0 && j >= 0){
sum = a.charAt(i) -'0' + b.charAt(j) -'0' + carry;
ans.append(sum % 2);
carry = sum / 2;
i--;
j--;
}
if(j>=0){
a = b;
i = j;
}
while(i>=0){
sum = a.charAt(i) -'0' + carry;
ans.append(sum % 2);
carry = sum / 2;
i--;
}
if(carry == 1){
ans.append('1');
}

change while(i >= 0 && j >= 0) into while(i >= 0 || j >= 0)

public String addBinary(String a, String b) {
StringBuilder ans = new StringBuilder();
int sum;
int i = a.length()-1;
int j = b.length()-1;
int carry = 0;
while(i >= 0 || j >= 0){
sum = carry;
if(i >= 0) sum += a.charAt(i) -'0';
if(j >= 0) sum += b.charAt(j) -'0';
ans.append(sum % 2);
carry = sum / 2;
i--;
j--;
}
if(carry == 1){
ans.append('1');
}
return ans.reverse().toString();
}

69. Sqrt(x)

69. Sqrt(x)

Given a non-negative integer x, compute and return the square root of x.
Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned.
Note: You are not allowed to use any built-in exponent function or operator, such as pow(x, 0.5) or x ** 0.5.

Input: x = 8
Output: 2
Explanation: The square root of 8 is 2.82842…, and since the decimal part is truncated, 2 is returned.

牛顿迭代法求平方根
F(x) = x^2 -b;
x2 = (x1+b/x1)/2
x2 x1无限逼近

要求是这样:输入一个数,输出其对应的平方根。

假设输入的数是 m,则其实是求一个 x 值,使其满足 x2 = m,令 f(x) = x2 - m ,其实就是求方程 f(x) = 0 的根。那么 f(x) 的导函数是 f’(x) = 2x。

那么 f(x) 函数的曲线在 (xn,xn2 - m) 处的切线的斜率是:2xn,因此切线方程是:y = 2xn (x - xn) + xn2 - m。故切线与x轴的交点是:xn+1 = (xn + m / xn ) / 2

根据牛顿迭代法,首先应该在曲线 f(x) 上任意选取一点,做切线。那么,我们直接把输入的数 m,作为选取的点的横坐标,即 x0 = m,然后根据上式进行迭代。

// using binary search
class Solution
{
public int mySqrt(int x) {
long ans;
ans = x;
while(ans * ans > x){
ans = (ans + (x/ans))/2;
}
return (int)ans;
}
}

70. Climbing Stairs

70. Climbing Stairs

You are climbing a staircase. It takes n steps to reach the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1 1 step + 1 step
2 2 steps

1 <= n <= 45

Recursion
Time Limit Exceeded

class Solution
{
public int climbStairs(int n) {
if(n==1) return 1;
if(n==2) return 2;
return climbStairs(n-1) + climbStairs(n-2);
}
}

DP

class Solution
{
public int climbStairs(int n) {
if(n <
3) return n;
int[] dp = new int[n+1];
dp[1] = 1;
dp[2] = 2;
for(int i = 3;i <= n;i++){
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}

71. Simplify Path

71. Simplify Path

Given a string path, which is an absolute path (starting with a slash ‘/’) to a file or directory in a Unix-style file system, convert it to the simplified canonical path.
In a Unix-style file system, a period ‘.’ refers to the current directory, a double period ‘…’ refers to the directory up a level, and any multiple consecutive slashes (i.e. ‘//’) are treated as a single slash ‘/’. For this problem, any other format of periods such as ‘…’ are treated as file/directory names.
The canonical path should have the following format:
The path starts with a single slash ‘/’.
Any two directories are separated by a single slash ‘/’.
The path does not end with a trailing ‘/’.
The path only contains the directories on the path from the root directory to the target file or directory (i.e., no period ‘.’ or double period ‘…’)
Return the simplified canonical path.

Example 1:
Input: path = “/home/”
Output: “/home”
Explanation: Note that there is no trailing slash after the last directory name.
Example 2:
Input: path = “/…/”
Output: “/”
Explanation: Going one level up from the root directory is a no-op, as the root level is the highest level you can go.
Example 3:
Input: path = “/home//foo/”
Output: “/home/foo”
Explanation: In the canonical path, multiple consecutive slashes are replaced by a single one.

class Solution
{
public String simplifyPath(String path) {
Stack<
String> stack = new Stack<
>();
String[] vals = path.split("/");
for(String val:vals){
if(val.equals("..") &&
!stack.isEmpty()){
stack.pop();
}
else if(!val.equals(".") &&
!val.equals("..") &&
!val.equals("")){
stack.push(val);
}
}
return "/"+String.join("/",stack);
}
}
  • String.split()

The string split() method breaks a given string around matches of the given regular expression. After splitting against the given regular expression, this method returns a String array.

  • Public String [ ] split ( String regex, int limit )
    Parameters:

    • regex – a delimiting regular expression
    • Limit – the resulting threshold

Returns: An array of strings is computed by splitting the given string.

Throws: PatternSyntaxException – if the provided regular expression’s syntax is invalid.

The limit parameter can have 3 values:

  • limit > 0 – If this is the case, then the pattern will be applied at most limit-1 times, the resulting array’s length will not be more than n, and the resulting array’s last entry will contain all input beyond the last matched pattern.
  • limit < 0 – In this case, the pattern will be applied as many times as possible, and the resulting array can be of any size.
  • limit = 0 – In this case, the pattern will be applied as many times as possible, the resulting array can be of any size, and trailing empty strings will be discarded.

Let the string that is to be split is – geekss@for@geekss

RegexLimitResult
@2{“geekss”, ”for@geekss”}
@5{“geekss”, ”for”, ”geekss”}
@-2{“geekss”, ”for”, ”geekss”}
s5{“geek”, ”“, “@for@geek”, “”, “”}
s-2{“geek”, ” “, ” “, “@for@geek”, “”, “”}
s0{“geek”, ””, ”@for@geek”}
  • String.equals()

The Java String class equals() method compares the two given strings based on the content of the string. If any character is not matched, it returns false. If all characters are matched, it returns true.

  • String.join()

The java.lang.string.join() method concatenates the given elements with the delimiter and returns the concatenated string.Note that if an element is null, then null is added.

String gfg1 = String.join(" < ", "Four", "Five", "Six", "Seven");
Four < Five < Six < Seven
String gfg2 = String.join(" ", "My", "name", "is", "Niraj", "Pandey");
My name is Niraj Pandey

72. Edit Distance

https://leetcode.com/problems/edit-distance/description/

Given two strings word1 and word2, return the minimum number of operations required to convert word1 to word2.
You have the following three operations permitted on a word:
Insert a character
Delete a character
Replace a character

Example 1:
Input: word1 = “horse”, word2 = “ros”
Output: 3
Explanation:
horse -> rorse (replace ‘h’ with ‘r’)
rorse -> rose (remove ‘r’)
rose -> ros (remove ‘e’)
Example 2:
Input: word1 = “intention”, word2 = “execution”
Output: 5
Explanation:
intention -> inention (remove ‘t’)
inention -> enention (replace ‘i’ with ‘e’)
enention -> exention (replace ‘n’ with ‘x’)
exention -> exection (replace ‘n’ with ‘c’)
exection -> execution (insert ‘u’)

Constraints:
0 <= word1.length, word2.length <= 500
word1 and word2 consist of lowercase English letters.

DP
dp[i][j] = the minimum steps to convert the first i characters of word1 (0,i) to the first j characters of word2 (0,j)

Base Cases:

If word1 is empty (i.e., i = 0), then we need j insertions to match word2[0…j-1]. Therefore, dp[0][j] = j.
If word2 is empty (i.e., j = 0), then we need i deletions to match word1[0…i-1]. Therefore, dp[i][0] = i.
Transition:

If the characters match (word1[i-1] == word2[j-1]), then no new operation is needed. Thus, dp[i][j] = dp[i-1][j-1].
If the characters don’t match, we consider three possible operations and choose the one with the minimum cost:
Insert a character: dp[i][j-1] + 1
Delete a character: dp[i-1][j] + 1
Replace a character: dp[i-1][j-1] + 1
So, dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 1).

word1 = “abc”,word2 = “abcd”
现在我们希望将 “abc” 变成 “abcd”,最简单的方法是在 abc 的末尾插入一个 d,所以 dp[3][4] = dp[3][3] + 1。

word1 = “abc”,word2 = “ab”
现在我们希望将 “abc” 变成 “ab”,我们可以通过删除 c 实现。所以 dp[3][2] = dp[2][2] + 1。

如果我们选择将 word1 的第 i 个字符替换为 word2 的第 j 个字符,那么 word1 的前 i-1 个字符需要转换为 word2 的前 j-1 个字符所需的操作次数是 dp[i-1][j-1]。
替换后,word1 的前 i 个字符就和 word2 的前 j 个字符匹配了,因此操作次数为 dp[i][j] = dp[i-1][j-1] + 1,其中 +1 表示替换操作。

class Solution
{
public int minDistance(String word1, String word2) {
//dp[i][j] = step to change (0,i) the same as (0,j)
int len1 = word1.length();
int len2 = word2.length();
int[][] dp = new int[len1+1][len2+1];
/*
charAt(i) charAt(j)
i == j dp[i][j] = dp[i-1][j-1]
i != j
insert dp[i][j] = dp[i][j-1] + 1
delete dp[i][j] = dp[i-1][j] + 1
replace dp[i][j] = dp[i-1][j-1] + 1
*/
for(int i = 0; i <= len2; i++){
dp[0][i] = i;
}
for(int i = 0; i <= len1; i++){
dp[i][0] = i;
}
for(int i = 1; i <= len1; i++){
for(int j = 1; j <= len2; j++){
if(word1.charAt(i-1)==word2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1];
}else{
dp[i][j] = Math.min(Math.min(dp[i][j-1],dp[i-1][j]),dp[i-1][j-1]) + 1;
}
}
}
return dp[len1][len2];
}
}

时间复杂度:O(m * n),因为我们需要填充大小为 m x n 的 DP 表,每个单元格的计算时间是常数。
空间复杂度:O(m * n),我们使用了大小为 m+1 x n+1 的二维数组。

73. Set Matrix Zeroes

73. Set Matrix Zeroes

Given an m x n integer matrix matrix, if an element is 0, set its entire row and column to 0’s.
You must do it in place.

Method 1
Use a visit array to distinguish between original 0 and created 0

class Solution
{
public void setZeroes(int[][] matrix) {
int i,j,x,y;
boolean[][] visit = new boolean[matrix.length][matrix[0].length];
for(i = 0; i < matrix.length; i++){
for(j = 0; j < matrix[0].length; j++ ){
if(visit[i][j] == false && matrix[i][j] == 0){
visit[i][j]=true;
for(x = 0; x < matrix.length; x++){
if(matrix[x][j] != 0 && visit[x][j] == false){
matrix[x][j] = 0;
visit[x][j] = true;
}
}
for(y = 0; y < matrix[0].length; y++){
if(matrix[i][y] != 0 && visit[i][y] == false){
matrix[i][y] = 0;
visit[i][y] = true;
}
}
}
}
}
}
}

There are repeat work. The time complexity is O(m*n)
Method 2
Use a symbol to mark whether the row or the column need to be changed.
Mark first, later transform together

public void setZeroes(int[][] matrix) {
int i,j;
boolean[] row_mark = new boolean[matrix.length];
boolean[] col_mark = new boolean[matrix[0].length];
for(i = 0; i < matrix.length; i++){
for(j = 0; j < matrix[0].length; j++){
if(matrix[i][j] == 0){
row_mark[i] = true;
col_mark[j] = true;
}
}
}
for(i = 0; i < matrix.length; i++){
for(j = 0; j < matrix[0].length; j++){
if(row_mark[i] == true || col_mark[j] == true){
matrix[i][j] = 0;
}
}
}
}

1ms 96.64% 54.5MB 20.75%

74. Search a 2D Matrix

74. Search a 2D Matrix

Write an efficient algorithm that searches for a value target in an m x n integer matrix matrix. This matrix has the following properties:
Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.

在这里插入图片描述

Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
Output: true

Binary Search
Method 1:
First select a proper row, then do binary search in that row.

class Solution
{
public boolean searchMatrix(int[][] matrix, int target) {
int rowLow = 0, rowHigh = matrix.length-1;
int colLow = 0, colHigh = matrix[0].length-1;
int rmid,cmid;
if(matrix[rowLow][0]>target) return false;
while(rowHigh>
0 && matrix[rowHigh][0]>target){
rowHigh--;
}
int x = rowHigh;
while(colLow<=colHigh){
cmid = colLow + (colHigh - colLow)/2;
if(matrix[x][cmid] == target){
return true;
}
if(matrix[x][cmid] > target){
colHigh = cmid - 1;
}
else{
colLow = cmid + 1;
}
}
return false;
}
}

Method 2:
Take the matrix as one row, the high index is row * col - 1. Do binary search in the whole matrix.

public boolean searchMatrix(int[][] matrix, int target) {
int row = matrix.length;
int col = matrix[0].length;
int low = 0;
int high = row * col - 1;
int mid;
while(low<=high){
mid = low + (high - low)/2;
int num = matrix[mid/col][mid%col];
if(num == target){
return true;
}
if(num > target){
high = mid -1;
}
else{
low = mid + 1;
}
}
return false;
}

75. Sort Colors

75. Sort Colors

Given an array nums with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white, and blue.
We will use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively.
You must solve this problem without using the library’s sort function.

Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

nums[i] is either 0, 1, or 2.

Follow up: Could you come up with a one-pass algorithm using only constant extra space?

Two-pass algorithm
Count the number of each color(0, 1, 2), assign the value to the nums array.
Use extra space.

class Solution
{
public void sortColors(int[] nums) {
//only 0 1 2
int[] count = new int[3];
for(int num:nums){
count[num]++;
}
int i = 0;
while(i<count[0]) nums[i++] = 0;
while(i<count[0]+count[1]) nums[i++] = 1;
while(i<nums.length) nums[i++] = 2;
return ;
}
}

One-pass algorithm
Quick Sort
Use start to put 0 at front. Use end to put 2 at back. Use I to move on the current index.
Start sits at the index next 0 should go. End sits at the next 2 should go.

start always <= index, so, when swap index and start, don’t need to check the value of start, is always 0.

class Solution
{
public void sortColors(int[] nums) {
int start = 0, end = nums.length - 1, index = 0;
while(index <= end && start < end) {
if(nums[index] == 0) {
//find zero, swap to the front
nums[index] = nums[start];
nums[start] = 0;
start++;
index++;
}
else if(nums[index] == 2){
//find two, swap to the end
nums[index] = nums[end];
nums[end] = 2;
end--;
// do not move the index because we don't know the value of nums[end]. we will check it in the next loop.
}
else{
//index == 1, move on
index++;
}
}
}
}

Use swap function

class Solution
{
public void sortColors(int[] nums) {
int start = 0, end = nums.length - 1, index = 0;
while(index <= end) {
if(nums[index] == 0)
//find zero, swap to the front
swap(nums, start++, index++);
else if(nums[index] == 2)
//find two, swap to the end
swap(nums, end--, index);
else
//index == 1, move on
index++;
}
}
public void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}

Quick Sort
Pseudo Code for recursive QuickSort function

quickSort(arr[], low, high) {
if (low < high) {
/* pi is partitioning index, arr[pi] is now at right place */
pi = partition(arr, low, high);
quickSort(arr, low, pi – 1);  // Before pi
quickSort(arr, pi + 1, high); // After pi
}
}

Pseudo code for partition()

/* This function takes last element as pivot,
places the pivot element at its correct position in sorted array,
and places all smaller to left of pivot and all greater elements to right of pivot */
partition (arr[], low, high){
// pivot (Element to be placed at right position)
pivot = arr[high];
i = (low – 1)  // Index of smaller element and indicates the
// right position of pivot found so far
for (j = low; j <= high- 1; j++){
// If current element is smaller than the pivot
if (arr[j] < pivot){
i++;    // increment index of smaller element
swap arr[i] and arr[j]
}
}
swap arr[i + 1] and arr[high])
return (i + 1)
}

Implementation of QuickSort using first element as pivot:

public int partition(int[] arr, int low, int high){
int start = low;
int pivot = arr[low];
while (low < high){
while (pivot >= arr[low])
low++;
while (pivot < arr[high])
high--;
if (low < high)
swap(arr[low], arr[high]);
}
swap(arr[start], arr[high]);
return high;
}
public void quickSort(int[] arr, int low, int high){
if (low < high){
int pivot = partition(arr, low, high);
quickSort(arr, low, pivot - 1);
quickSort(arr, pivot + 1, high);
}
}

quicksort递归,退出条件为low>=high,即区间为一个字符

swap(arr[start], arr[high]);
return high;

arr[start] start存储的pivot的位置,经过 while (low < high){} 交换后,low==high,high的左边是val<pivot 右边是val>pivot, 最后将high/low的位置交换放置pivot,并且返回pivot的坐标

76. Minimum Window Substring

76. Minimum Window Substring

Given two strings s and t of lengths m and n respectively, return the minimum window
substring
of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string “”.
The testcases will be generated such that the answer is unique.

Example 1:
Input: s = “ADOBECODEBANC”, t = “ABC”
Output: “BANC”
Explanation: The minimum window substring “BANC” includes ‘A’, ‘B’, and ‘C’ from string t.
Example 2:
Input: s = “a”, t = “a”
Output: “a”
Explanation: The entire string s is the minimum window.
Example 3:
Input: s = “a”, t = “aa”
Output: “”
Explanation: Both 'a’s from t must be included in the window.
Since the largest window of s only has one ‘a’, return empty string.

Constraints:
m == s.length
n == t.length
1 <= m, n <= 105
s and t consist of uppercase and lowercase English letters.
Follow up: Could you find an algorithm that runs in O(m + n) time?

sliding window
怎么统计字符出现的频率

用一个hashmap或者array 对t统计字符频率++,对s统计时,如果值大于0–,

HashMap.get() It returns NULL when the map contains no such mapping for the key.
HashMap.getOrDefault(key,defaultValue);

滑动窗口双指针,怎么判断left和right是否该移动

右指针扩展窗口:当当前窗口不满足要求时,右指针应该继续向右移动来扩展窗口。
左指针收缩窗口:当当前窗口满足要求时,左指针应该尽量向右移动来收缩窗口,以寻找更小的符合条件的窗口。

右指针无条件移动

class Solution
{
private boolean valid(HashMap<
Character,Integer> map){
for (int count : map.values()) {
if (count >
0) {
return false;
}
}
return true;
}
public String minWindow(String s, String t) {
int left = 0,right = 0;
HashMap<
Character,Integer> map = new HashMap<
>();
for(char c:t.toCharArray()){
if(map.containsKey(c)){
map.put(c,map.get(c)+1);
}else{
map.put(c,1);
}
}
int min = Integer.MAX_VALUE;
int minLeft = 0;
int minRight = 0;
while(right < s.length()){
char cr = s.charAt(right);
if(map.containsKey(cr))
map.put(cr,map.get(cr)-1);
while(valid(map)){
if(right-left+1 < min){
min = right-left+1;
minLeft = left;
minRight = right;
}
char cl = s.charAt(left);
if(map.containsKey(cl)){
map.put(cl,map.get(cl)+1);
}
left++;
}
right++;
}
if(min == Integer.MAX_VALUE){
return "";
}
return s.substring(minLeft,minRight+1);
}
}

77. Combinations

77. Combinations

given two integers n and k, return all possible combinations of k numbers out of the range [1, n].
You may return the answer in any order.

Input: n = 4, k = 2
Output:
[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4]]

(n m) = n! / k! (n - k)!
Backtracking
Backtacking has a decision tree.
1-> 2 1->3 1->4 2->3 2->4 3->4
The height of the dicision tree is k.

class Solution
{
public static List<
List<
Integer>
> combine(int n, int k) {
List<
List<
Integer>
> combs = new ArrayList<
List<
Integer>
>();
combine(combs, new ArrayList<
Integer>(), 1, n, k);
return combs;
}
public static void combine(List<
List<
Integer>
> combs, List<
Integer> comb, int start, int n, int k) {
if(k == 0) {
combs.add(new ArrayList<
Integer>(comb));
return;
}
for(int i = start; i <= n; i++) {
comb.add(i);
combine(combs, comb, i+1, n, k-1);
comb.remove(comb.size()-1);
}
}
}

18ms 80.44% 43.1MB 99.54%

i + k -1 <= n;

for(int i = start;i <= n - k + 1; i++) {
comb.add(i);
combine(combs, comb, i+1, n, k-1);
comb.remove(comb.size()-1);
}

2ms 98.64% 54.2MB 79.43%

We also can use LinkedList because it is easy to remove the last node.

List<
List<
Integer>
> combs = new LinkedList<
List<
Integer>
>();
comb.removeLast();
lists.add(new ArrayList<
Integer>(list));

78. Subsets

78. Subsets

Given an integer array nums of unique elements, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.

Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

Backtracking

class Solution
{
public List<
List<
Integer>
> subsets(int[] nums) {
List<
List<
Integer>
> ans = new ArrayList<
>();
List<
Integer> temp = new ArrayList<
>();
backtrack(ans,temp,nums,0);
return ans;
}
private void backtrack(List<
List<
Integer>
> ans,List<
Integer> temp,int[] nums,int i){
ans.add(new ArrayList<
Integer>(temp));
if(i>=nums.length){
return;
}
for(int j = i;j < nums.length;j++){
temp.add(nums[j]);
backtrack(ans,temp,nums,j+1);
temp.remove(temp.size()-1);
}
return ;
}
}

79. Word Search

79. Word Search

Given an m x n grid of characters board and a string word, return true if word exists in the grid.
The word can be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once.

在这里插入图片描述

Input: board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
Output: true

Recursion + backtracking

class Solution
{
boolean[][] visit;
public boolean exist(char[][] board, String word) {
visit = new boolean[board.length][board[0].length];
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
if(board[i][j]== word.charAt(0) &&
search(board,word,0,i,j)){
return true;
}
}
}
return false;
}
private boolean search(char[][] board, String word, int index, int x, int y){
if(index == word.length()){
return true;
}
//out of boundary
if(x <
0 || x >= board.length || y <
0 || y >= board[0].length ||visit[x][y] == true || board[x][y]!=word.charAt(index)){
return false;
}
visit[x][y] = true;
if(search(board,word,index+1,x+1,y) || search(board,word,index+1,x,y+1) || search(board,word,index+1,x-1,y) || search(board,word,index+1,x,y-1)){
return true;
}
visit[x][y] = false;
return false;
}
}

80. Remove Duplicates from Sorted Array II

80. Remove Duplicates from Sorted Array II

Given an integer array nums sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears at most twice. The relative order of the elements should be kept the same.
Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements.
Return k after placing the final result in the first k slots of nums.
Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory.

Input: nums = [1,1,1,2,2,3]
Output: 5, nums = [1,1,2,2,3,_]
Explanation: Your function should return k = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).

two pointer
Record the two nodes ahead the current node and compare the value with current node.
Use index i to travese, k to represent new array’s index.

class Solution
{
public int removeDuplicates(int[] nums) {
int k = 0;
int i;
int pre,prepre;
if(nums.length<=2){
return nums.length;
}
pre = nums[1];
prepre = nums[0];
k = 2;
for(i = 2; i < nums.length;i++){
if(pre==prepre && nums[i]==pre){
continue;
}
nums[k++] = nums[i];
prepre = pre;
pre = nums[i];
}
return k;
}
}

81. Search in Rotated Sorted Array II

81. Search in Rotated Sorted Array II

There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).
Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]] (0-indexed). For example, [0,1,2,4,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].
Given the array nums after the rotation and an integer target, return true if target is in nums, or false if it is not in nums.
You must decrease the overall operation steps as much as possible.

Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true

Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false

public boolean search(int[] nums, int target) {
int low = 0, high = nums.length-1;
while(low<=high){
if(nums[low] == target || nums[high] == target) return true;
if(nums[low]<target) low++;
else if(nums[high]>target) high--;
else return false;
}
return false;
}
public boolean search(int[] nums, int target) {
List<
Integer> list = new ArrayList<
>();
for(int num:nums){
list.add(num);
}
return list.contains(target);
}
class Solution
{
public boolean search(int[] nums, int target) {
int low = 0,high = nums.length-1;
int mid = 0;
while(low<=high){
mid = (low + high)/2;
if(target == nums[mid]) return true;
//mid与左右顶点比较 
//判断target应该属于的部分
if(nums[mid]>=nums[low]){
//[4,5,6,7,0,1,2] 0
//low-mid属于左部分 左递增
if(target<nums[mid] && target >=nums[low]){
//target在左部分
//[4,5,6,7,0,1,2] 3 [4,5,6,7,0,1,2] 6
high = mid - 1;
}
else{
low = mid + 1;
}
}
else if(nums[mid]<=nums[high]){
//mid-high属于右部分 右递增
//[5,6,7,0,1,2,3] 4 [5,6,7,0,1,2,3] 6
if(target > nums[mid] && target <=nums[high]){
low = mid + 1;
}
else{
high = mid - 1;
}
}
}
return false;
}
}

82. Remove Duplicates from Sorted List II

82. Remove Duplicates from Sorted List II

Given the head of a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. Return the linked list sorted as well.

Input: head = [1,2,3,3,4,4,5]
Output: [1,2,5]

Two pointers
pre current / head

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution
{
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null) return head;
ListNode dummy_head = new ListNode();
dummy_head.next = head;
ListNode pre = dummy_head;
while(head!=null){
if(head.next!=null && head.val == head.next.val){
while(head.next!=null && head.val == head.next.val){
head = head.next;
}
pre.next = head.next;
}
else{
pre = head;
}
head = head.next;
}
return dummy_head.next;
}
}

83. Remove Duplicates from Sorted List

83. Remove Duplicates from Sorted List

Given the head of a sorted linked list, delete all duplicates such that each element appears only once. Return the linked list sorted as well.

Input: head = [1,1,2]
Output: [1,2]

Method 1
Delete the duplicate node
If next node.val is equal to current node. Skip the next node. Test the new next node after current node.

class Solution
{
public ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
while(current!=null && current.next!=null){
if(current.val == current.next.val){
current.next = current.next.next;
}else{
current = current.next;
}
}
return head;
}
}

Method 2
Make a new linkedlist. Set pre to be the last node of the new list.
If the val of p is different with the val of pre, link p to the new list and update.

class Solution
{
public ListNode deleteDuplicates(ListNode head) {
if(head == null) return head;
ListNode pre = head;
ListNode p = head.next;
while(p != null){
if(pre.val == p.val){
pre.next = p.next;
p = pre.next;
}
else{
pre = pre.next;
p = p.next;
}
}
return head;
}
}

86. Partition List

86. Partition List

Given the head of a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.

Input: head = [1,4,3,2,5,2], x = 3
Output: [1,2,2,4,3,5]

Truncate the linkedlist into 2 parts, smaller and bigger. Move the small node on the bigger list to the small list.

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution
{
public ListNode partition(ListNode head, int x) {
if(head==null || head.next==null)
return head;
ListNode newHead = new ListNode();
ListNode smallHead = newHead;
smallHead.next = head;
while(smallHead.next!=null && smallHead.next.val<x){
smallHead = smallHead.next;
}
if(smallHead.next==null){
return newHead.next;
}
ListNode bigHead = smallHead.next;
ListNode p = bigHead.next;
ListNode pre = bigHead;
while(p!=null){
if(p.val<x){
pre.next = p.next;
smallHead.next = p;
smallHead = p;
p = pre.next;
}
else{
p = p.next;
pre = pre.next;
}
}
smallHead.next = bigHead;
return newHead.next;
}
}

0ms 100% 41.5MB 96.84%

88. Merge Sorted Array

88. Merge Sorted Array

You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements in nums1 and nums2 respectively.
Merge nums1 and nums2 into a single array sorted in non-decreasing order.
The final sorted array should not be returned by the function, but instead be stored inside the array nums1. To accommodate this, nums1 has a length of m + n, where the first m elements denote the elements that should be merged, and the last n elements are set to 0 and should be ignored. nums2 has a length of n.

Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
Explanation: The arrays we are merging are [1,2,3] and [2,5,6].
The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1.

Extra space
Use a new array. Insert the small element. Copy the array into nums1.

No extra space
move nums1 back

class Solution
{
public void merge(int[] nums1, int m, int[] nums2, int n) {
int length = m + n;
int i = length -1, j = 0, k = 0;
while(i>=n){
nums1[i] = nums1[i-n];
i--;
}
i = n;
while(i<length &
& i > 0 && j<n){
if(nums1[i] <= nums2[j]){
nums1[k++] = nums1[i++];
}
else{
nums1[k++] = nums2[j++];
}
}
while(i<length &
& i>0){
nums1[k++] = nums1[i++];
}
while(j < n){
nums1[k++] = nums2[j++];
}
return ;
}
}

Start from the biggest element and insert it into the back of the nums1.

class Solution
{
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1;
int j = nums2.length-1;
int k = nums1.length-1;
while(i >= 0 && j >= 0){
if(nums1[i]>=nums2[j]){
nums1[k--] = nums1[i--];
}else{
nums1[k--] = nums2[j--];
}
}
while(i >= 0){
nums1[k--] = nums1[i--];
}
while(j >= 0){
nums1[k--] = nums2[j--];
}
}
}

89. Gray Code

89. Gray Code

An n-bit gray code sequence is a sequence of 2n integers where:
Every integer is in the inclusive range [0, 2n - 1],
The first integer is 0,
An integer appears no more than once in the sequence,
The binary representation of every pair of adjacent integers differs by exactly one bit, and
The binary representation of the first and last integers differs by exactly one bit.
Given an integer n, return any valid n-bit gray code sequence.

Input: n = 2
Output: [0,1,3,2]
Explanation:
The binary representation of [0,1,3,2] is [00,01,11,10].
00 and 01 differ by one bit
01 and 11 differ by one bit
11 and 10 differ by one bit
10 and 00 differ by one bit
[0,2,3,1] is also a valid gray code sequence, whose binary representation is [00,10,11,01].
00 and 10 differ by one bit
10 and 11 differ by one bit
11 and 01 differ by one bit
01 and 00 differ by one bit

90. Subsets II

90. Subsets II

Given an integer array nums that may contain duplicates, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.

Input: nums = [1,2,2]
Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]

backtracking
skip duplicate

class Solution
{
public List<
List<
Integer>
> subsetsWithDup(int[] nums) {
List<
List<
Integer>
> ansList = new ArrayList<
>();
List<
Integer> ans = new ArrayList<
>();
Arrays.sort(nums);
backtrack(nums,ansList,ans,0);
return ansList;
}
private void backtrack(int[] nums,List<
List<
Integer>
> ansList, List<
Integer> ans, int n) {
if(n>nums.length) return;
ansList.add(new ArrayList<
Integer>(ans));
for(int i = n; i< nums.length; i++){
ans.add(nums[i]);
backtrack(nums,ansList,ans, i + 1);
ans.remove(ans.size() - 1);
while (i+1 < nums.length && nums[i+1] == nums[i]) i++;
}
return;
}
}

2ms 84.28% 44.5MB 24.43%

private void backtrack(int[] nums,List<
List<
Integer>
> ansList,List<
Integer> ans,int n){
if(n>nums.length) return;
if(!ansList.contains(ans)){
ansList.add(new ArrayList<
Integer>(ans));
}
for(int i = n; i < nums.length; i++){
ans.add(nums[i]);
backtrack(nums,ansList,ans,i+1);
ans.remove(ans.size()-1);
}
}

17ms

91. Decode Ways

91. Decode Ways

A message containing letters from A-Z can be encoded into numbers using the following mapping:
‘A’ -> “1”
‘B’ -> “2”

‘Z’ -> “26”
To decode an encoded message, all the digits must be grouped then mapped back into letters using the reverse of the mapping above (there may be multiple ways). For example, “11106” can be mapped into:
“AAJF” with the grouping (1 1 10 6)
“KJF” with the grouping (11 10 6)
Note that the grouping (1 11 06) is invalid because “06” cannot be mapped into ‘F’ since “6” is different from “06”.
Given a string s containing only digits, return the number of ways to decode it.
The test cases are generated so that the answer fits in a 32-bit integer.

Input: s = “12”
Output: 2
Explanation: “12” could be decoded as “AB” (1 2) or “L” (12).

DP
dp[ i ] : the number of the possible result
if 10< (s.charAt( i ) s.charAt( i+1 ) ) <= 26:
2 result : 12 -> 1,2 / 12

12 2: 1 2 12
122 3: 1 2 2 12 2 1 22
1222 5:1 2 2 2 12 22 1 2 22 12 2 2 1 22 2

class Solution
{
public int numDecodings(String s) {
if(s.charAt(0)=='0')
return 0;
//dp[0]=0 [1]-[n] store result 
int[] dp = new int[s.length()+1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i<=s.length();i++){
if(s.charAt(i-1)<='9' && s.charAt(i-1)>
'0'){
//初始dp[i] 0 只有一种可能 0+1 dp[i] += dp[i-1];
dp[i] += dp[i-1];
//只有一种解的情况下,继承前一位的解数
}
if((s.charAt(i-2)=='1')||(s.charAt(i-2)=='2' && s.charAt(i-1)<='6')){
//10-19 20-26
//前一位与当前位可以组合成一种新的可能 即在当前解数的基础上,多一种解的可能
// XXXX A B XXXX AB 默认是XXXX A B 多的XXXX AB增加的解数为XXXX的解数
dp[i] += dp[i-2];
}
}
return dp[s.length()];
}
}

92. Reverse Linked List II

92. Reverse Linked List II

Given the head of a singly linked list and two integers left and right where left <= right, reverse the nodes of the list from position left to position right, and return the reversed list.

Input: head = [1,2,3,4,5], left = 2, right = 4
Output: [1,4,3,2,5]

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution
{
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode preHead = new ListNode();
preHead.next = head;
ListNode pre = preHead;
int countl = 0, countr = 0;
left--;
while(pre.next!=null && countl < left){
//move pre to the previous node of the left
pre = pre.next;
countl++;
}
ListNode rear = pre;
countr = countl;
while(rear!=null && countr <= right){
//move rear to the rear node of the right
rear = rear.next;
countr++;
}
//头插法逆链
ListNode present = pre.next.next;
ListNode temp;
pre.next.next = rear;
while(present!=rear){
temp = present.next;
present.next = pre.next;
pre.next = present;
present = temp;
}
return preHead.next;
}
}

93. Restore IP Addresses

93. Restore IP Addresses

A valid IP address consists of exactly four integers separated by single dots. Each integer is between 0 and 255 (inclusive) and cannot have leading zeros.
For example, “0.1.2.201” and “192.168.1.1” are valid IP addresses, but “0.011.255.245”, “192.168.1.312” and “192.168@1.1” are invalid IP addresses.
Given a string s containing only digits, return all possible valid IP addresses that can be formed by inserting dots into s. You are not allowed to reorder or remove any digits in s. You may return the valid IP addresses in any order.

Input: s = “25525511135”
Output: [“255.255.11.135”,“255.255.111.35”]

94. Binary Tree Inorder Traversal

94. Binary Tree Inorder Traversal

Given the root of a binary tree, return the inorder traversal of its nodes’ values.

Input: root = [1,null,2,3]
Output: [1,3,2]

DFS
Recursive Approach

left root right

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution
{
List<
Integer> ans = new ArrayList<
> ();
public List<
Integer> inorderTraversal(TreeNode root) {
if(root==null) return ans;
if(root.left!=null) inorderTraversal(root.left);
ans.add(root.val);
if(root.right!=null) inorderTraversal(root.right);
return ans;
}
}

Iterating method using Stack
stack继承vector有效率问题,不推荐使用
建议使用deque实现栈

class Solution
{
public List<
Integer> inorderTraversal(TreeNode root) {
List<
Integer> ans = new ArrayList<
>();
Deque<
TreeNode> stack = new ArrayDeque<
>();
TreeNode p = root;
while (p != null || stack.size()!=0 ){
while (p != null) {
stack.offerFirst(p);
p = p.left;
}
p = stack.pollFirst();
ans.add(p.val);
p = p.right;
}
return ans;
}
}

0 ms 100.00% 40.5 MB 90.38%

class Solution
{
public List<
Integer> inorderTraversal(TreeNode root) {
List<
Integer> ans = new ArrayList<
>();
Stack<
TreeNode> stack = new Stack<
>();
TreeNode p = root;
while(p!=null || !stack.isEmpty()){
while(p!=null){
stack.push(p);
p = p.left;
}
p = stack.pop();
ans.add(p.val);
p = p.right;
}
return ans;
}
}

递归,对于当前一个点root,先把它的所有左节点压入栈。最先出栈的是最左,出栈访问再看有没有右子树,把右子树root变为当前节点

PreOrder

PostOrder

InOrder

95. Unique Binary Search Trees II

95. Unique Binary Search Trees II

Given an integer n, return all the structurally unique BST’s (binary search trees), which has exactly n nodes of unique values from 1 to n. Return the answer in any order.

Input: n = 3
Output: [[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]

Every 1-n number can be the root. Numbers in left subtree are smaller andin right subtree are bigger.

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution
{
public List<
TreeNode> generateTrees(int n) {
return generateTrees(1,n);
}
public List<
TreeNode> generateTrees(int start,int end){
List<
TreeNode> trees = new ArrayList<
TreeNode>();
if(start>end){ trees.add(null);
return trees;
}
for(int rootValue=start;rootValue<=end;rootValue++){
List<
TreeNode> leftSubTrees=generateTrees(start,rootValue-1);
List<
TreeNode> rightSubTrees=generateTrees(rootValue+1,end);
for(TreeNode leftSubTree:leftSubTrees){
for(TreeNode rightSubTree:rightSubTrees){
TreeNode root=new TreeNode(rootValue);
root.left=leftSubTree;
root.right=rightSubTree;
trees.add(root);
}
}
}
return trees;
}
}

96. Unique Binary Search Trees

96. Unique Binary Search Trees

Given an integer n, return the number of structurally unique BST’s (binary search trees) which has exactly n nodes of unique values from 1 to n.

Input: n = 3
Output: 5

DP
for 1-n: Accumulate all possible solutions with 1-n as root
G(i,n): The number of solutions with i as root and total length n
Total solutions: F(n) = sum(G(i,n))
After determining the root, possible solutions = the number of possible solutions of the left subtree * the number of possible solutions of the right subtree
G(i,n) = F(i-1)*F(n-i)

F(n) = G(1,n)+G(2,n)+G(3,n)+……+G(n,n)
F(n) = F(0)*F(n-1)+F(1)*F(n-2)+F(2)*F(n-3)……+F(n-2)*F(1)+F(n-1)*F(0);
F(0) = 1 F(1)=1 F(2)=F(0)*F(1) F(3)=F(0)*F(2)+F(1)*F(1)+F(2)*F(0)

class Solution
{
public int numTrees(int n) {
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++){
for(int j = 1; j <= i; j++)
dp[i] += dp[j-1]*dp[i-j];
}
return dp[n];
}
}

97. Interleaving String

97. Interleaving String

Given strings s1, s2, and s3, find whether s3 is formed by an interleaving of s1 and s2.
An interleaving of two strings s and t is a configuration where they are divided into non-empty substrings such that:
s = s1 + s2 + … + sn
t = t1 + t2 + … + tm
|n - m| <= 1
The interleaving is s1 + t1 + s2 + t2 + s3 + t3 + … or t1 + s1 + t2 + s2 + t3 + s3 + …
Note: a + b is the concatenation of strings a and b.

Follow up: Could you solve it using only O(s2.length) additional memory space?

brute force

class Solution
{
public boolean isInterleave(String s1, String s2, String s3) {
// Check if lengths match
if (s1.length() + s2.length() != s3.length()) {
return false;
}
return isInterleaveHelper(s1, 0, s2, 0, s3, 0);
}
private boolean isInterleaveHelper(String s1, int i, String s2, int j, String s3, int k) {
// Base case: if we've reached the end of s3, return true
if (k == s3.length()) {
return true;
}
// Check if the current character of s3 can be formed by the current character of s1
boolean match1 = (i < s1.length() && s1.charAt(i) == s3.charAt(k))
&&
isInterleaveHelper(s1, i + 1, s2, j, s3, k + 1);
// Check if the current character of s3 can be formed by the current character of s2
boolean match2 = (j < s2.length() && s2.charAt(j) == s3.charAt(k))
&&
isInterleaveHelper(s1, i, s2, j + 1, s3, k + 1);
// If either match1 or match2 is true, s3 can be formed
return match1 || match2;
}
}

DP
dp[i][j] 来表示 s1 的前 i 个字符和 s2 的前 j 个字符能否交错组成 s3 的前 i+j 个字符。

base case:
dp[0][0] = true;
s1 == null : dp[i][0] = dp[i-1][0];

class Solution
{
public boolean isInterleave(String s1, String s2, String s3) {
int m = s1.length(), n = s2.length();
// If the lengths don't match, it's not possible to interleave
if (m + n != s3.length()) {
return false;
}
boolean[][] dp = new boolean[m + 1][n + 1];
// Initialize the DP table
dp[0][0] = true;
for(int i = 1; i <= len1; i++){
if(s1.charAt(i-1)==s3.charAt(i-1)){
dp[i][0] = dp[i-1][0];
}
}
for(int i = 1; i <= len2; i++){
if(s2.charAt(i-1)==s3.charAt(i-1)){
dp[0][i] = dp[0][i-1];
}
}
// Fill in the rest of the DP table
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1))
|| (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1));
}
}
return dp[m][n];
}
}

Wrong:

for(int i = 1; i <= len1; i++){
for(int j = 1; j <= len2; j++){
if(s3.charAt(i + j -1)==s1.charAt(i-1)){
dp[i][j] = dp[i-1][j];
}else if(s3.charAt(i + j -1)==s2.charAt(j-1)){
dp[i][j] = dp[i][j-1];
}else{
dp[i][j] = false;
}
}
}

因为可能 s3[i+j-1] 同时等于 s1[i-1] 和 s2[j-1],这时需要考虑两种情况。而你的代码只处理了一个条件,并且没有正确地组合 dp[i][j] 的值。
此外,如果当前字符匹配不成功,你的代码直接将 dp[i][j] 设为 false,但实际上应该是在前一个状态不满足的前提下再设为 false。

98. Validate Binary Search Tree

98. Validate Binary Search Tree

Given the root of a binary tree, determine if it is a valid binary search tree (BST).
A valid BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.

Input: root = [2,1,3]
Output: true

Traverse and check left subtree and right subtree. If it is not a BST, return false.

Resursion
Inorder traverse: left < root < right. Increasing.

edge condition: root == null -> true;

validate left sub tree first: 1. if true, continue validate root: 1-1. if true, validate right sub tree: 1-1-1: if true, return true. 1-1-2. else return false 1-2. else, return false 2. else, return false

TreeNode prev = null;
public boolean isValidBST(TreeNode root) {
if(root == null) {
return true;
}
if(isValidBST(root.left) &&
(prev == null || root.val > prev.val)) {
prev = root;
return isValidBST(root.right);
}
return false;
}

Resursion Use extra helper function

Inorder traverse: left < root < right

Use the previous and rear value to check the current node, if true, continue to check the left and right sub tree

public boolean isValidBST(TreeNode root) {
return helper(root, null, null);
}
boolean helper(TreeNode root, Integer min, Integer max) {
if (root == null)
return true;
if ((min != null && root.val <= min) || (max != null && root.val >= max))
return false;
return helper(root.left, min, root.val) &&
helper(root.right, root.val, max);
}

1ms 59.57% 44.5MB 18.58%
Use stack to traverse inorder. Check when popping out.

class Solution
{
public boolean isValidBST(TreeNode root) {
TreeNode pre = null;
Stack<
TreeNode> stack = new Stack<
>();
while(!stack.isEmpty() || root!=null){
while(root!=null){
stack.push(root);
root = root.left;
}
root = stack.pop();
if(pre!=null && root.val <= pre.val){
return false;
}
pre = root;
root = root.right;
}
return true;
}
}

2ms 23.06% 42.1MB 83.78%

99. Recover Binary Search Tree

99. Recover Binary Search Tree

You are given the root of a binary search tree (BST), where the values of exactly two nodes of the tree were swapped by mistake. Recover the tree without changing its structure.

Input: root = [1,3,null,null,2]
Output: [3,1,null,null,2]
Explanation: 3 cannot be a left child of 1 because 3 > 1. Swapping 1 and 3 makes the BST valid.

在这里插入图片描述
Exact one swap needed for this question, find the first wrong one and last wrong one, swap.

class Solution
{
// Creating three global pointers
TreeNode previous = null;
TreeNode first = null;
TreeNode second = null;
public void recoverTree(TreeNode root) {
// Finding the two swapped nodes
solve(root);
//Swaping the value of nodes
int temp = first.val;
first.val = second.val;
second.val = temp;
}
//New Function to find the two nodes
public void solve(TreeNode root){
if(root == null){
return;
}
//Doing inorder traversal i.e, sarting from left then right
solve(root.left);
// If current node is smaller than previous, then previous node is invalid
if(previous != null && root.val < previous.val){
//Storing previous node
if(first == null){
first = previous;
}
//If both nodes are adjacent, save the current node in that case
second = root;
}
//Making current node as previous node
previous = root;
//Moving to right sub-tree
solve(root.right);
}
}

100. Same Tree

100. Same Tree

Given the roots of two binary trees p and q, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical, and the nodes have the same value.

Input: p = [1,2,3], q = [1,2,3]
Output: true

recursion

class Solution
{
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null && q==null) return true;
if(p==null || q==null) return false;
if(p.val==q.val)
return isSameTree(p.left,q.left) &&
isSameTree(p.right,q.right);
else
return false;
}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/917996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

西安网站建设流程海南平台网站建设平台

目录 依赖项:timm库。 cuda版1060显卡运行时间 14ms左右 高通不支持gelu激活函数 需要的 SqueezeExcite代码,不是SqueezeExcite_o

福州网站排名买车看车app排行榜

可编辑(一) 像素函数56. putpiel() 画像素点函数57. getpixel()返回像素色函数(二) 直线和线型函数58. line() 画线函数59. lineto() 画线函数60. linerel() 相对画线函数61. setlinestyle() 设置线型函数62. getlinesettings() 获取线型设置函数63. setwritemode() 设置画线模…

如何通过 Python + Selenium + BeautifulSoup 爬取动态加载的网页数据 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

实用指南:【连载6】 C# MVC 日志管理最佳实践:归档清理与多目标输出配置

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025Unity必备知识——GUI(完整详细) - 指南

2025Unity必备知识——GUI(完整详细) - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", &q…

HBM之父:HBM的终点是HBF

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087韩国半导体公司SK海力士日前宣布,已完成下一代超高性能AI存储器产…

深圳哪家建设网站公司好网页链接打不开是什么原因

12天 本节学习了基于MindSpore的GPT2文本摘要。 1.数据集加载与处理 1.1.数据集加载 1.2.数据预处理 2.模型构建 2.1构建GPT2ForSummarization模型 2.2动态学习率 3.模型训练 4.模型推理

实用指南:40.应用层协议HTTP(三)

实用指南:40.应用层协议HTTP(三)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco…

建德市住房和城乡建设局网站制作公司官网的步骤

目录 1 搭建嵌入式gdb调试环境 1.1 交叉编译工具链自带的gdb和gdbserver 1.2 使用gdb进行嵌入式程序调试 1.2.1编写简单测试程序 1.2.2 gdb调试程序 1.3 源码编译gdb和gdbserver 1.3.1 下载gdb和gdbserver源码 1.3.2 编译gdb 1.3.3 移植gdbserver 2 VSCodegdbserver 图…

南宁制作网站网页代码大全

我初始化h2数据库&#xff0c; 然后把jar 放到 springside-4.0.0.RC2\examples\mini-web 中 &#xff0c;最后配置启动tomcat。 就出现这个错。 最开始我用 quick-start.bat &#xff0c;但总是执行到一半就 挂掉了。 提示spy 包没找到 。 这个是在装载 xml&#xff0c;解析成b…

网站建设调研提纲wordpress评论页面

目录 1. 文本分类 2. 图像识别 3. 生物信息学 4. 金融预测 5. 其他领域 1. 文本分类 垃圾邮件过滤&#xff1a;SVM通过训练大量标记为垃圾邮件和非垃圾邮件的样本&#xff0c;学习出能够区分两者的模型&#xff0c;从而实现对新邮件的自动分类。情感分析&#xff1a;在社…

【GitHub每日速递 250926】12 周 24 课,边学边练!微软 AI 初学者的通关秘籍

原文:https://mp.weixin.qq.com/s/t99TeeaVhDTuzobY6WkYng 揭秘Linera:高可扩展区块链基础设施,附CLI工具快速上手攻略 linera-protocol 是一个基于Rust构建的高性能、去中心化微服务区块链协议的底层框架。简单讲,…

mcp-use mcp server 交互工具

mcp-use mcp server 交互工具mcp-use mcp server 交互工具,当然mcp-use 不支持简单的mcp client,还支持agent开发,通过mcp-use 我们可以将llm 与mcp server 集成起来,提升agent 的能力 简单示例 import asyncio i…

年薪破百万、涨薪60%,人形机器人企业疯狂「抢人」

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 35469554100490872025年,人形机器人不再只是春晚舞台上的炫技明星,而是逐渐走进具…

深入解析:HttpClientFactory vs new HttpClient:.NET Core HTTP 客户端的正确打开方式

深入解析:HttpClientFactory vs new HttpClient:.NET Core HTTP 客户端的正确打开方式2025-09-26 08:01 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important;…

石家庄整站优化技术园区网互联及网站建设项目

目录 统一数据返回一. 概念二.实现统一数据返回2.1 重写responseAdvice方法2.2 重写beforeBodyWriter方法 三. 特殊类型-String的处理四. 全部代码 统一数据返回 一. 概念 其实统一数据返回是运用了AOP&#xff08;对某一类事情的集中处理&#xff09;的思维&#xff0c;简单…

自助建个人网站哪个好购物网站框架

在 PHP 中&#xff0c;多进程的处理通常会遇到一些挑战&#xff0c;比如资源共享、进程间通信、性能优化等。Swoole 是一个高性能的协程和多进程框架&#xff0c;旨在为 PHP 提供异步、并发、协程等功能&#xff0c;解决了传统 PHP 环境中的多进程管理问题。通过使用 Swoole&am…

华为投的这家上海独角兽,要IPO了!

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087近日,赛美特信息集团股份有限公司(以下简称“赛美特”)正式向港…

0134_委托模式 (Delegate)

委托模式 (Delegate) 意图 两个对象参与处理同一个请求,接收请求的对象将请求委托给另一个对象来处理。 委托模式的核心思想是:一个对象将某些职责交给另一个专门的对象去完成,从而实现职责的分离和代码的复用。 UM…

外贸网站建设公司平台中建国能建设集团网站

强烈建议去看看《上海交通大学生存手册》&#xff0c;内容可能有点长&#xff0c;但讲得很好&#xff0c;说出了大学教育的本质。如果几年前我能看到它&#xff0c;也许我的大学生活可能会不一样。 只是&#xff0c;没有如果。 那么我把这本手册推荐给正在上大学或者是将要上…