560. Subarray Sum Equals K

Given an array of integers nums and an integer k, return the total number of subarrays whose sum equals to k.

对于数组中每个数字,计算其前缀的和。
前缀[i]减去前缀[j]的差,等于[j]-[i]之间数字的和。(类似一种DP,数组可以用一个变量代替。)

因此,原题目等于寻找找 前缀[i]-前缀[j] = k。
用哈希表储存已经遍历过的前缀和出现的次数。
每次遍历时先查看哈希表内是否有当前[前缀和-k]的键在。
如果有则加入到count中。
(哈希表中需要提前放入一个0键,值等于1,为了计算[前缀和-k]等于0的情况。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public int subarraySum(int[] nums, int k) {

int[] sum = new int[nums.length + 1];
HashMap<Integer, Integer> map = new HashMap();
int count = 0;
map.put(0, 1);

for(int i = 1; i <= nums.length; i++){
sum[i] = sum[i-1] + nums[i-1];
count += map.getOrDefault(sum[i]-k, 0);
map.put(sum[i], map.getOrDefault(sum[i], 0) + 1);
}

return count;
}
}

238. Product of Array Except Self

Given an integer array nums, return an array answer such that answer[i] is equal to the product of all the elements of nums except nums[i].

The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.

You must write an algorithm that runs in O(n) time and without using the division operation.

当前数字之外的积等于左边所有数字的积乘以右边所有数字的积。
因此可以维护两个数组,分别计算从左到右的乘积,和从右到左的乘积。

由于返回答案不算占用空间,因此可以将左侧乘积的数组保存在答案数组上。
然后在遍历时,从右至左遍历,使用一个变量储存右边的乘积,直接将两者的乘积更新在答案数组上。
此时空间复杂度为O(1)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int[] productExceptSelf(int[] nums) {
int[] ans = new int[nums.length];
ans[0] = 1;

for(int i = 1; i < nums.length; i++){
ans[i] = ans[i-1] * nums[i-1];
}

int rightProduct = 1;

for(int j = nums.length-1; j >=0; j--){
ans[j] = ans[j] * rightProduct;
rightProduct *= nums[j];
}
return ans;
}
}

438. Find All Anagrams in a String

Given two strings s and p, return an array of all the start indices of p’s anagrams in s. You may return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

滑动窗口。采用两个数组分别计算两个字符串中字符出现的数量。

滑动窗口时,维护数组中字符串中字符出现的次数。
循环,判断两个字符串是否相等,如果相等,则将当前的左指针添加进答案。
移动窗口的左右指针,在数组中减少前一项出现的次数,增加后一项出现的次数。

通过维护一个表示两个字符串中字符差值的数组,可以将算法优化算法,而不必进行两个数组的比较。

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
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> ans = new ArrayList();
if(p.length()>s.length()){
return ans;
}

int[] alphabet = new int[26];
int[] window = new int[26];

for(int i = 0; i < p.length(); i++){
alphabet[p.charAt(i) - 'a']++;
window[s.charAt(i) - 'a']++;
}

int i = 0;
int j = p.length();

while(j < s.length()){
if(Arrays.equals(alphabet, window)){
ans.add(i);
}
window[s.charAt(i) - 'a']--;
window[s.charAt(j) - 'a']++;
i++;
j++;
}

if(Arrays.equals(alphabet, window)){
ans.add(i);
}

return ans;

}
}

334. Increasing Triplet Subsequence

Given an integer array nums, return true if there exists a triple of indices (i, j, k) such that i < j < k and nums[i] < nums[j] < nums[k]. If no such indices exists, return false.

贪心算法。
将first与second初始化为最大值。
first保存遍历过的最小值。
second保存遍历过的大于之前最小值的最小值。

遍历数组。
条件一:如果数字小于现在第一个值,则更新第一个值。
(此时一定不满足条件二,因此可以安全地更新更小的数字。)
条件二:如果数字大于第一个值,且小于第二个值,则更新第二个值。
(此时第一个值已经被更新过了,满足第一个值小于第二个值。)
条件三:如果数字大于第二个值,则返回true。
(此时两个值一定都被更新过了,满足第一个值小于第二个值小于第三个值。)

注意:
更新first后,second不会更新,但是second的存在可以确保曾经存在first小于second。
如果此时数字大于second,则数组中存在Triplet Subsequence。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public boolean increasingTriplet(int[] nums) {
int first = Integer.MAX_VALUE;
int second = Integer.MAX_VALUE;

for(int num : nums){
if(num < first){
first = num;
}
else if(num > first && num < second){
second = num;
}
else if(num > second){
return true;
}
}
return false;
}
}

双向遍历,逐渐收紧搜索窗口。设置i,k两个指针分别在头尾。
当nums[j] <= nums[i],则更新i指针为j。
当nums[j] >= nums[k],则更新k指针为j。
如果找到符合条件的nums[i] < nums[j] < nums[k]则返回。

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
37
38
39
40
41
42
class Solution {
public boolean increasingTriplet(int[] nums) {
boolean flag = true;
int i = 0;
int k = nums.length -1 ;
int j;
int count = 1;

while(i < k && i + count < k){
if(flag){
j = i + count;
if(nums[i] >= nums[j]){
i = j;
count = 1;
flag = true;
continue;
}
else if(nums[j] < nums[k]){
return true;
}
flag = !flag;
}
else{
j = k - count;
if(nums[k] <= nums[j]){
k = j;
count = 1;
flag = true;
continue;
}
else if(nums[j] > nums[i]){
return true;
}
else{
count++;
}
flag = !flag;
}
}
return false;
}
}

173. Binary Search Tree Iterator

Implement the BSTIterator class that represents an iterator over the in-order traversal of a binary search tree (BST):

BSTIterator(TreeNode root) Initializes an object of the BSTIterator class. The root of the BST is given as part of the constructor. The pointer should be initialized to a non-existent number smaller than any element in the BST.
boolean hasNext() Returns true if there exists a number in the traversal to the right of the pointer, otherwise returns false.
int next() Moves the pointer to the right, then returns the number at the pointer.
Notice that by initializing the pointer to a non-existent smallest number, the first call to next() will return the smallest element in the BST.

You may assume that next() calls will always be valid. That is, there will be at least a next number in the in-order traversal when next() is called.

此方法不用将所有节点一次性入栈,而是在获得next时更新栈内的节点,因此更省时间。
将根节点的所有左子节点入栈,此时栈顶为最小值。
next方法:返回当前的栈顶节点。如果栈顶节点存在右子节点,则将其所有的左子节点入栈。
hasNext方法:返回栈是否为空的非值。

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
37
38
39
40
41
42
43
44
45
46
/**
* 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 BSTIterator {
Stack<TreeNode> stack;
public BSTIterator(TreeNode root) {
stack = new Stack();
updateStack(root);
}

public int next() {
TreeNode node = stack.pop();
updateStack(node.right);
return node.val;
}

public boolean hasNext() {
return !stack.isEmpty();
}

private void updateStack(TreeNode root){
while(root != null){
stack.push(root);
root = root.left;
}
}
}

/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator obj = new BSTIterator(root);
* int param_1 = obj.next();
* boolean param_2 = obj.hasNext();
*/

DFS搜索,中序搜索,从右子节点至左子节点,先将所有元素入栈。
next方法:挤出栈顶并返回。
hasNext方法: 返回栈是否为空的非值。

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
37
38
39
40
41
42
43
44
45
46
/**
* 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 BSTIterator {
Stack<TreeNode> stack;
public BSTIterator(TreeNode root) {
stack = new Stack();
initiateStack(root);
}

public int next() {
return stack.pop().val;
}

public boolean hasNext() {
return !stack.isEmpty();
}

private void initiateStack(TreeNode root){
if(root == null){
return;
}
initiateStack(root.right);
stack.push(root);
initiateStack(root.left);
}
}

/**
* Your BSTIterator object will be instantiated and called as such:
* BSTIterator obj = new BSTIterator(root);
* int param_1 = obj.next();
* boolean param_2 = obj.hasNext();
*/

986. Interval List Intersections

You are given two lists of closed intervals, firstList and secondList, where firstList[i] = [starti, endi] and secondList[j] = [startj, endj]. Each list of intervals is pairwise disjoint and in sorted order.

Return the intersection of these two interval lists.

A closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b.

The intersection of two closed intervals is a set of real numbers that are either empty or represented as a closed interval. For example, the intersection of [1, 3] and [2, 4] is [2, 3].

设置两个指针,分别指向两个intervals的头部。
循环,相交的left等于两者左端的较大值。right等于两者右端的较小值。
只有在left小于right时,两个interval才相交,填入列表。
然后更新两个interval中右端较小的指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
List<int[]> ans = new ArrayList();
int i = 0;
int j = 0;

while(i < firstList.length && j < secondList.length){
int left = Math.max( firstList[i][0], secondList[j][0] );
int right = Math.min( firstList[i][1], secondList[j][1] );
if(left <= right){
ans.add(new int[]{left, right});
}
if(firstList[i][1] < secondList[j][1]) i++;
else j++;

}

int[][] ret = new int[ans.size()][2];
ans.toArray(ret);
return ret;
}
}
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
37
38
39
40
41
42
43
44
45
46
class Solution {
public int[][] intervalIntersection(int[][] firstList, int[][] secondList) {
int i = 0;
int j = 0;
ArrayList<int[]> ans = new ArrayList();
int[] holdA;
int[] holdB;

while(i < firstList.length && j < secondList.length){
holdA = firstList[i];
holdB = secondList[j];

int[] arr = new int[2];

if(holdA[0] <= holdB[0] && holdA[1] >= holdB[1]){
ans.add(holdB);
j++;
}
else if(holdA[0] >= holdB[0] && holdA[1] <= holdB[1]){
ans.add(holdA);
i++;
}
else if(holdA[0] <= holdB[0] && holdA[1] >= holdB[0]){
arr[0] = holdB[0];
arr[1] = holdA[1];
ans.add(arr);
i++;
}
else if(holdA[0] >= holdB[0] && holdB[1] >= holdA[0]){
arr[0] = holdA[0];
arr[1] = holdB[1];
ans.add(arr);
j++;
}
else if(holdA[1] <= holdB[1]){
i++;
}
else{
j++;
}
}
int[][] ret = new int[ans.size()][2];
ans.toArray(ret);
return ret;
}
}

844. Backspace String Compare

Given two strings s and t, return true if they are equal when both are typed into empty text editors. '#' means a backspace character.

Note that after backspacing an empty text, the text will continue empty.

辅助方法getNextValid,返回下一个有效值。
将两个指针分别设置在两个字符串的尾部。
当两指针有一个大于0时,进行循环。
每次都搜索两个指针的下一个有效值。
如果两个指针上的字符不同则返回false。

最后返回两个指针的停留位置是否相同。

注意:
如果有一个字符串指针先更新到0以下,另一个指针仍有可能更新到一个“#”字符位置。
此时最后的结应该是两个空字符串。
因此需要继续循环一次,得出其是否会归到零以下。如果此时归零则两者的指针位置仍然相等。

因此即使getNextValid返回的下一个值为负数也应该保留其数值。

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
class Solution {
public boolean backspaceCompare(String s, String t) {
int i = s.length()-1;
int j = t.length()-1;

while(i >= 0 || j >= 0){
i = getNextValid(s, i);
j = getNextValid(t, j);
if( i >= 0 && j >= 0 && s.charAt(i) != t.charAt(j)){
return false;
}
i--;
j--;
}
return (i == j);
}

private int getNextValid(String s, int start){
int i = start;
int count = 0;
while(i >= 0 && (s.charAt(i) == '#' || count != 0)){
if(s.charAt(i) == '#'){
count++;
}
else{
count--;
}
i--;
}
return i;
}
}

435. Non-overlapping Intervals

Given an array of intervals intervals where intervals[i] = [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.

首先对intervals按照后一项的大小进行排序。(直接将两数字相减作为比较值比Integer.compare方法更快。)
贪心算法,将已取得的最大值max设置为最小整数值。
遍历intervals,如果当前interval的左侧小于max,则不能选择该interval,计数加一。
反之则可以选择interval,更新max的值为interval的最大值。
返回总数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
Arrays.sort(intervals, (a,b) -> a[1] - b[1]);
int max = Integer.MIN_VALUE;
int count = 0;
for(int[] interval : intervals){
if(interval[0] < max){
count++;
}
else{
max = interval[1];
}
}
return count;
}
}

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.

DFS中序搜索,额外记录访问的前一个节点。
如果当前节点与前一个节点的顺序不对,则暂且认为先后两个节点的位置均不正确。
(前一个大于后一个的值,由于是第一个不满足递增条件的位置,因此前一个的位置一定是错误的。但此时当前值不一定是错误的。)
继续递归,如果发现新的节点位置不正确,则后一个节点位置正确,更新当前节点为不正确的节点。
(由于是第二个不满足递增条件的位置,因此当前值是错误的。)
交换两个位置不正确的节点的值。

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
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* 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 {
TreeNode prev;
boolean flag;
TreeNode[] wrong;
public void recoverTree(TreeNode root) {
wrong = new TreeNode[2];
prev = new TreeNode(Integer.MIN_VALUE);
flag = true;

dfs(root);

int swap = wrong[0].val;
wrong[0].val = wrong[1].val;
wrong[1].val = swap;


}

private void dfs(TreeNode root){
if(root == null){
return;
}
dfs(root.left);
if(prev.val > root.val){
if(flag){
wrong[0] = prev;
flag = false;
}
wrong[1] = root;
}
prev = root;
dfs(root.right);
}
}

230. Kth Smallest Element in a BST

Given the root of a binary search tree, and an integer k, return the kth smallest value (1-indexed) of all the values of the nodes in the tree.

DFS搜索,遍历的时候更新全局变量count。
采用中序搜索,当count等于k时,将全局变量ans设置为root.val。
搜索完毕返回ans。

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
37
/**
* 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 {
int ans;
int count;
public int kthSmallest(TreeNode root, int k) {
ans = -1;
count = 0;
dfs(root,k);
return ans;
}

private void dfs(TreeNode root, int k){
if(root == null){
return;
}
dfs(root.left,k);
count++;
if (k == count){
ans = root.val;
}
dfs(root.right,k);
}
}
240. Search a 2D Matrix II

240. Search a 2D Matrix II

Question

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 in ascending from left to right.
  • Integers in each column are sorted in ascending from top to bottom.

Solution

将起始点设置为第一行的最后一列。
如果搜寻目标大于该点则向下搜索。
如果搜寻目标小于该点则向左搜索。

Code

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int i = 0, j = matrix[0].length - 1;

while(i < matrix.length && j >= 0){
if(matrix[i][j] == target) return true;
else if(matrix[i][j] > target) j--;
else i++;
}
return false;
}
}

119. Pascal's Triangle II

Given an integer rowIndex, return the rowIndexth (0-indexed) row of the Pascal’s triangle.

In Pascal’s triangle, each number is the sum of the two numbers directly above it as shown:

根据杨辉三角形的规则递归。
每次递归行数-1。
根据上一行的返回值,生成新行的列表,然后返回。
如果生成行数为0则返回{1}。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public List<Integer> getRow(int rowIndex) {
if(rowIndex == 0){
List<Integer> ret = new ArrayList();
ret.add(1);
return ret;
}

List<Integer> arr = getRow(rowIndex - 1);
List<Integer> ret = new ArrayList();

for(int i = 0; i < arr.size()+1; i++){
if(i == 0 || i == arr.size()){
ret.add(1);
}
else{
ret.add(arr.get(i) + arr.get(i-1));
}
}
return ret;
}
}

706. Design HashMap

Design a HashMap without using any built-in hash table libraries.

Implement the MyHashMap class:

MyHashMap() initializes the object with an empty map.
void put(int key, int value) inserts a (key, value) pair into the HashMap. If the key already exists in the map, update the corresponding value.
int get(int key) returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key.
void remove(key) removes the key and its corresponding value if the map contains the mapping for the key.

哈希表,先设置一个素数Prime作为map的尺寸。
(这里设置成素数是为了减少可能的碰撞。)
创建一个Pair类记录key和value。

map初始化时需要生成一个LinkedList数组。

  • hash方法计算哈希值。用key % Prime并返回。
  • put方法,根据key计算其哈希值h。如果列表中有则重新设置当前Pair的value。
  • get方法,根据哈希值h搜索并查找链表中的Pair,如果找到则返回Pair,否则返回-1。
  • remove方法,根据哈希值h搜索并remove链表中的Pair。
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
class MyHashMap {
final int PRIME = 1009;
List<Pair>[] map;
public MyHashMap() {
map = new LinkedList[PRIME];
for(int i = 0; i < PRIME; i++){
map[i] = new LinkedList<Pair>();
}
}

public void put(int key, int value) {
int h = hash(key);
for(Pair p : map[h]){
if(p.getKey() == key){
p.setValue(value);
return;
}
}
Pair p = new Pair(key, value);
map[h].add(p);
}

public int get(int key) {
int h = hash(key);
for(Pair p : map[h]){
if(p.getKey() == key){
return p.value;
}
}
return -1;
}

public void remove(int key) {
int h = hash(key);
for(Pair p : map[h]){
if(p.getKey() == key){
map[h].remove(p);
return;
}
}
}

private int hash(int key){
return key % PRIME;
}
}

class Pair {
int key;
int value;
public Pair(int k, int v){
key = k;
value = v;
}

public int getKey(){
return key;
}
public int getValue(){
return value;
}
public void setValue(int v){
value = v;
}
}

/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap obj = new MyHashMap();
* obj.put(key,value);
* int param_2 = obj.get(key);
* obj.remove(key);
*/

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.

先对数组进行排序。
遍历数组,当前一个子数组与后一个子数组有重叠时,合并数组。

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 {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a,b) -> Integer.compare(a[0],b[0]));

int i = 0;
List<int[]> ans = new ArrayList();
while( i < intervals.length-1 ){
if(intervals[i][1] >= intervals[i+1][0]){
intervals[i+1][0] = intervals[i][0];
intervals[i+1][1] = Math.max(intervals[i][1], intervals[i+1][1]);
intervals[i] = null;
}
i++;
}

for(int[] interval : intervals){
if(interval != null){
ans.add(interval);
}
}
return ans.toArray(new int[ans.size()][2]);
}
}

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.

使用队列暂存遍历的节点。
初始化prev为一个dummy节点。
如果当前节点不等于队列里节点的值,则倾倒出队列里的值。如果队列此时只有一个值,则将其添加到prev.next。
遍历完毕后如果队列内只有一个值则将其设置到prev.next。
最后返回dummy.next。

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
37
38
39
40
41
/**
* 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) {
Queue<ListNode> q = new LinkedList();
ListNode dummy = new ListNode(0);
ListNode prev = dummy;
ListNode curr = head;
while(curr != null){
if(q.isEmpty() || curr.val == q.peek().val){
q.offer(curr);
curr = curr.next;
}
else{
if(q.size()==1){
prev.next = q.poll();
prev = prev.next;
prev.next = null;
}
else{
q.clear();
}
}
}

if(q.size()==1){
prev.next = q.poll();
}

return dummy.next;
}

}