86. Partition List

86. Partition List

Question

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.

Solution 1

生成前后两个部分的dummy链表头。
遍历原链表,当当前值小于x时则将当前节点添加到第一个链表头后。
当当前值大于x时则将当前节点添加到第二个链表头后。

遍历完成后将第二个链表头的下一个节点添加到第一个链表的下一个节点上。然后将第二个链表的尾部指向null。

返回第一个dummy链表节点的下一个节点即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 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) {
ListNode dummy1 = new ListNode(), dummy2 = new ListNode();
ListNode hd1 = dummy1, hd2 = dummy2;
while(head != null){
if(head.val < x){
dummy1.next = head;
dummy1 = dummy1.next;
}
else{
dummy2.next = head;
dummy2 = dummy2.next;
}
head = head.next;
}
dummy1.next = hd2.next;
dummy2.next = null;

return hd1.next;
}
}

Solution 2

遍历整个链表,根据各个节点的值将其保存在两个队列中。

设置一个dummy节点头,将两个队列中的节点按顺序挤出并生成新链表。
返回dummy节点头的下一个节点即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* 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) {
Queue<ListNode> q1 = new LinkedList<>();
Queue<ListNode> q2 = new LinkedList<>();
while(head != null){
if(head.val < x) q1.add(head);
else q2.add(head);
head = head.next;
}

ListNode dummy = new ListNode();
ListNode res = dummy;

while(!q1.isEmpty()){
res.next = q1.poll();
res = res.next;
}

while(!q2.isEmpty()){
res.next = q2.poll();
res = res.next;
}
res.next = null;
return dummy.next;
}
}
576. Out of Boundary Paths

576. Out of Boundary Paths

Question

There is an m x n grid with a ball. The ball is initially at the position [startRow, startColumn]. You are allowed to move the ball to one of the four adjacent cells in the grid (possibly out of the grid crossing the grid boundary). You can apply at most maxMove moves to the ball.

Given the five integers m, n, maxMove, startRow, startColumn, return the number of paths to move the ball out of the grid boundary. Since the answer can be very large, return it modulo 109 + 7.

Solution

DFS,记忆化搜索哦剪枝。

记忆化搜索

三维数组memo[][][]用来记录起点为startRow, startColumn,剩余距离为maxMove时的总路径数。
注意需要将memo[][][]所有数值初始化为-1。否则在进行BFS搜索时,无法对maxMove等于0的情况进行剪枝。

DFS

当当前位置越界,则为一个有效路径,返回1。
当剩余步数为0时,无法继续移动,返回0。

如果当前位置与剩余步数的状态已经被搜索并记录过,则直接返回memo[startRow][startColumn][maxMove]。
如果未搜索,则将maxMove减一,并向四周移动一格,对当前位置的四个方向进行递归。
记忆当前位置的四个方向的总路径数之和,模除后返回。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
final int MOD = (int) Math.pow(10, 9) + 7;
long[][][] memo;
public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
memo = new long[m][n][maxMove];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
for(int k = 0; k < maxMove; k++){
memo[i][j][k] = -1;
}
}
}
return (int) dfs(m, n, maxMove, startRow, startColumn);
}

private long dfs(int m, int n, int maxMove, int startRow, int startColumn){
if(startRow < 0 || startRow >= m || startColumn < 0 || startColumn >= n) return 1;
if(maxMove == 0) return 0;

maxMove--;
if(memo[startRow][startColumn][maxMove] != -1) return memo[startRow][startColumn][maxMove];

long left = dfs(m, n, maxMove, startRow-1, startColumn);
long right = dfs(m, n, maxMove, startRow+1, startColumn);
long up = dfs(m, n, maxMove, startRow, startColumn+1);
long down = dfs(m, n, maxMove, startRow, startColumn-1);

memo[startRow][startColumn][maxMove] = (left + right + up + down) % MOD;
return memo[startRow][startColumn][maxMove];
}
}
473. Matchsticks to Square

473. Matchsticks to Square

Question

You are given an integer array matchsticks where matchsticks[i] is the length of the ith matchstick. You want to use all the matchsticks to make one square. You should not break any stick, but you can link them up, and each matchstick must be used exactly one time.

Return true if you can make this square and false otherwise.

Solution

回溯,用int[] edges记录边长。

先计算所有火柴棍的长度之和是否能被4整除,如果不能则返回false。
将所有火柴排序,以减少回溯时的计算量。

Backtracking 回溯

当遍历越界时(传入index为-1),则返回true。

每次将当前火柴matchsticks[index]添加到一个edges[i]中。
当edges[i] <= sum / 4,且向前回溯前一个位置index-1返回结果为真,则返回true。
然后将当前火柴从edges[i]中取出。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
int[] edges;
public boolean makesquare(int[] matchsticks) {
int sum = 0;
for(int i = 0; i < matchsticks.length; i++) sum += matchsticks[i];
if(sum % 4 != 0) return false;

edges = new int[4];
Arrays.sort(matchsticks);
return backtracking(matchsticks, matchsticks.length-1, sum/4);
}

public boolean backtracking(int[] matchsticks, int index, int len){
if(index == -1) return true;

for(int i = 0; i < 4; i++){
edges[i] += matchsticks[index];
if(edges[i] <= len && backtracking(matchsticks, index - 1, len)) return true;
edges[i] -= matchsticks[index];
}
return false;
}
}
746. Min Cost Climbing Stairs

746. Min Cost Climbing Stairs

Question

You are given an integer array cost where cost[i] is the cost of ith step on a staircase. Once you pay the cost, you can either climb one or two steps.

You can either start from the step with index 0, or the step with index 1.

Return the minimum cost to reach the top of the floor.

Solution

动态规划,每一个新位置的等于前一个位置加上其cost和前两个位置加上cost的较小值。

Code

1
2
3
4
5
6
7
8
9
class Solution {
public int minCostClimbingStairs(int[] cost) {
int[] dp = new int[cost.length+1];
for(int i = 2; i <= cost.length; i++){
dp[i] = Math.min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2]);
}
return dp[cost.length];
}
}
509. Fibonacci Number

509. Fibonacci Number

Question

The Fibonacci numbers, commonly denoted F(n) form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. That is,

F(0) = 0, F(1) = 1
F(n) = F(n - 1) + F(n - 2), for n > 1.

Given n, calculate F(n).

Solution 1

记忆化搜索,在递归时递归过的n放入数组memo中记录。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
int[] memo;
public int fib(int n) {
if(n == 0 || n == 1) return n;
memo = new int[n+1];
return fibo(n);
}

private int fibo(int n){
if(n == 0 || n == 1) return n;
if(memo[n] == 0) memo[n] = fibo(n-1) + fibo(n-2);
return memo[n];
}
}

Solution 2

递归,当n等于0或者1时返回固定值。
否则返回fib(n-1)+fib(n-2)。

Code

1
2
3
4
5
6
class Solution {
public int fib(int n) {
if(n == 0 || n == 1) return n;
return fib(n-1) + fib(n-2);
}
}