162. Find Peak Element

A peak element is an element that is strictly greater than its neighbors.

Given an integer array nums, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.

You may imagine that nums[-1] = nums[n] = -∞.

You must write an algorithm that runs in O(log n) time.

二分搜索,由于只需要搜索任意一个山峰,因此只要向上走,一定可以走到一个峰。
当中值的下一个值是增长时(向上爬山),则更新左侧指针的位置为中值+1。继续搜索下一个中值。
否则更新右侧指针的位置为当前中值,等于向左侧进行搜索。
最后返回左侧指针停留的位置。
时间复杂度为O(logn)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public int findPeakElement(int[] num) {
int left = 0;
int right = num.length - 1;

while (left < right) {
int mid1 = (right - left) / 2 + left;
int mid2 = mid1 + 1;
if (num[mid1] < num[mid2])
left = mid1+1;
else
right = mid1;
}
return left;
}
}

一次遍历,找到峰值,返回其index。
时间复杂度为O(n)。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int findPeakElement(int[] nums) {
int peak = 0;

for(int i = 0; i < nums.length; i++){
if(nums[i] > nums[peak]){
peak = i;
}
}
return peak;
}
}

分治法,每次将数组分为两组,向下递归。
当数组长度为1时返回元素,比较返回来的两个数值的大小。
返回其中的峰值index。
此解法时间为O(nlogn)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int findPeakElement(int[] nums) {
return findPeak(nums,0,nums.length-1);
}

private int findPeak(int[] nums, int left, int right){
if(left == right){
return left;
}
int mid = left + (right - left) / 2;
int i = findPeak(nums, left, mid);
int j = findPeak(nums, mid+1, right);

if(nums[i] > nums[j]){
return i;
}
else{
return j;
}
}
}
48. Rotate Image

48. Rotate Image

Question

You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise).

You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.

Solution 1

此方法是in-place算法。

visited[][]数组记录访问情况,遍历所有位置,如果已访问则跳过。
循环替换矩阵上的每一个位置,如果已经访问过则break。
如果未访问则将要替换位置的值保存,并且在visited[][]数组上记录。
然后继续遍历替换过的位置。

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
class Solution {
public void rotate(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[][] visited = new int[m][n];

for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(visited[i][j] == 1) continue;
int x = i, y = j;
int value = matrix[i][j];
while(true){
int s = n-1-x, t = y;
if(visited[t][s] == 1) break;
int temp = matrix[t][s];
matrix[t][s] = value;
value = temp;
visited[t][s] = 1;
x = t;
y = s;
}
}
}
}
}

Solution 2

此方法类似Solution 1,但是并非原地算法。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public void rotate(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[][] mat = new int[m][n];

for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
int s = n-1-i, t = j;
mat[t][s] = matrix[i][j];
}
}
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
matrix[i][j] = mat[i][j];
}
}
}
}

Solution 3

辅助方法getPixel计算旋转后的像素位置。
旋转时候矩阵内的四个分区的像素会互相替换。
因此需要将需要旋转的初始位置记录进入队列。
旋转图像时根据getPixel方法计算出需要替换的位置。
然后依次替换像素。

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
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
Queue<Integer> queue = new LinkedList();
for (int p = 0; p < n/2; p++){
for(int q = 0; q < (n+1)/2; q++){
queue.offer(p * n + q);
}
}

while(!queue.isEmpty()){
int i = queue.poll();
int INDEX = i;
boolean flag = true;
int temp = matrix[i/n][i%n];
while(i != INDEX || flag ){
flag = false;
int j = getPixel(n, i);
int swap = matrix[j / n][j % n];
matrix[j / n][j % n] = temp;
temp = swap;
i = j;
}
}
}

private int getPixel(int n, int o){
int row = o / n;
int col = o % n;
int newRow = col;
int newCol = n - (row + 1);
return (newRow * n) + newCol;
}
}

153. Find Minimum in Rotated Sorted Array

Suppose an array of length n sorted in ascending order is rotated between 1 and n times. For example, the array nums = [0,1,2,4,5,6,7] might become:

  • [4,5,6,7,0,1,2] if it was rotated 4 times.
  • [0,1,2,4,5,6,7] if it was rotated 7 times.

Notice that rotating an array [a[0], a[1], a[2], …, a[n-1]] 1 time results in the array [a[n-1], a[0], a[1], a[2], …, a[n-2]].

Given the sorted rotated array nums of unique elements, return the minimum element of this array.

You must write an algorithm that runs in O(log n) time.

二分搜索,寻找断裂点。
当left小于right时循环。
每次计算出mid,分为两种情况:

  • 如果nums[mid]小于nums[nums.length-1],则右半侧为顺序的。
  • 反之则左半侧为顺序,右半侧为无序的。
    以此来更新搜索范围。
    由于mid计算公式向下取整。
    当更新left时更新为mid+1,向前一格。
    当更新right时更新为mid。
    最后返回nums[left]。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int findMin(int[] nums) {
return findBreakPoint(nums,0,nums.length-1);
}

private int findBreakPoint(int[] nums, int left, int right){
while(left < right){
int mid = (right - left)/2 + left;
if(nums[mid] < nums[nums.length-1]){
right = mid;
}
else if(nums[mid] >= nums[0]){
left = mid+1;
}

}
return nums[left];
}
}

897. Increasing Order Search Tree

Given the root of a binary search tree, rearrange the tree in in-order so that the leftmost node in the tree is now the root of the tree, and every node has no left child and only one right child.

DFS搜索,在递归时将in-order遍历节点,并将其加入队列。
从队列中挤出节点,将上一个节点的右子节点设置为下一个节点。
同时需要将下一个节点的左子节点设置为null。
`

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
/**
* 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 {
Queue<TreeNode> q;
public TreeNode increasingBST(TreeNode root) {
q = new LinkedList();
dfs(root);
TreeNode head = q.poll();
TreeNode curr = head;
while(!q.isEmpty()){
curr.left = null;
curr.right = q.poll();
curr = curr.right;
}
curr.left = null;
return head;
}

private void dfs(TreeNode root){
if(root == null){
return;
}
dfs(root.left);
q.offer(root);
dfs(root.right);
}
}

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.

快速排序是原地排序,因此此问题可以采用快速排序解决。

选择left上的元素pivot,设置一个指针index为left+1。
遍历left+1至right的数组,如果遍历的值小于pivot则将nums[i]与nums[index]交换,然后将index向右移动。

因此index左侧的元素均小于pivot,index右侧的元素均大于pivot。
最后将nums[index]与pivot交换,此时pivot左侧元素均小于它,右侧元素均大于它,因此index不需要再动。
然后分别向下递归left至index-1,index+1至right。

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
class Solution {
public void sortColors(int[] nums) {
quickSort(nums, 0, nums.length-1);
}

private void quickSort(int[] nums, int left, int right){
if( right - left < 1 ){
return;
}
int pivot = nums[left];
int index = left+1;
for(int i = index; i <= right; i++){
if(nums[i] < pivot){
int temp = nums[index];
nums[index] = nums[i];
nums[i] = temp;
index++;
}
}
index--;

nums[left] = nums[index];
nums[index] = pivot;

quickSort(nums,left,index-1);
quickSort(nums,index+1,right);
}
}

33. Search in Rotated Sorted Array

There is an integer array nums sorted in ascending order (with distinct values).

Prior to being passed to your function, nums is possibly rotated at an unknown pivot index k (1 <= 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,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].

Given the array nums after the possible rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.

You must write an algorithm with O(log n) runtime complexity.

二分搜索,二分后将会形成两个区间,一个区间是顺序的,另一个是无序的。
如果target等于中间值则返回。
分别处理两种情况下移动指针的方式。
当顺序区间在左半边时:
当target在顺序区间内,则更新右指针的位置。
否则更新左指针位置。
当顺序区间在右半边时:
当target在顺序区间内,则更新左指针的位置。
否则更新右指针位置。

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
class Solution {
public int search(int[] nums, int target) {

int left = 0;
int right = nums.length-1;

while(left <= right){
int mid = (right - left) / 2 + left;
if(nums[mid] == target){
return mid;
}

if( nums[mid] >= nums[0] ){
if(target >= nums[0] && target < nums[mid] ){
right = mid - 1;
}
else{
left = mid + 1;
}
}
else{
if(target > nums[mid] && target <= nums[nums.length-1]){
left = mid + 1;
}
else{
right = mid -1;
}
}

}
return -1;
}
}

15. 3Sum

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.

Notice that the solution set must not contain duplicate triplets.

三数之和,重点是如何遍历后去除重复的数组。
首先对数组进行排序。
遍历数组,三个数中最小的数字为nums[i]。
此时需要去除重复的nums[i]。如重复则继续下一次循环。
此时设置双指针left和right,分别在nums[i]右侧的子数组的首尾。

  • 当nums[i] + nums[left] + nums[right] > 0时,后两个数的和需要减小,right指针向左移动。
  • 当nums[i] + nums[left] + nums[right] < 0时,后两个数的和需要增大,left指针向右移动。
  • 当nums[i] + nums[left] + nums[right] = 0时,找到一个组合。
    此时需要去除重复的nums[left]和nums[right]。如重复则更新left或right的指针。
  • 将组合添加到返回列表。

最后返回列表。

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
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList();
Arrays.sort(nums);

for(int i = 0; i < nums.length; i++){
int left = i+1;
int right = nums.length-1;
if(i>0 && nums[i] == nums[i-1]){
continue;
}

while(left < right){
if(nums[i]+nums[left]+nums[right]==0){
while(left+1 < nums.length && nums[left] == nums[left+1]){
left++;
}
while(right-1 > i && nums[right] == nums[right-1]){
right--;
}
List<Integer> list = new ArrayList();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
ans.add(list);

left++;
right--;
}
else if(nums[i]+nums[left]+nums[right]>0){
right--;
}
else{
left++;
}
}
}
return ans;
}
}

34. Find First and Last Position in Sorted Array

问题
Given an array of integers nums sorted in non-decreasing order, find the starting and ending position of a given target value.

If target is not found in the array, return [-1, -1].

You must write an algorithm with O(log n) runtime complexity.

二分搜索,搜索中间项。
中间项等于左侧和右侧指针的中点,根据搜索左侧边界和右侧边界选择二分向下舍去或是二分向上补足。
当中间项小于目标,则更新左侧边界。
若中间项大于目标,则更新右侧边界。
当中间项等于目标时,根据搜索左侧边界还是右侧边界选择更新左侧或右侧。
由于有可能有重复元素存在,因此需要继续二分搜索下去,直到右侧边界大于左侧边界。

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
class Solution {
public int[] searchRange(int[] nums, int target) {
return new int[]{searchLeft(nums,target),searchRight(nums,target)};
}

private int searchRight(int[] nums, int target){
int left = 0;
int right = nums.length-1;
int mid = 0;
int result = -1;

while(left <= right){
mid = (right-left)/2+left;
if(nums[mid] < target){
left = mid+1;
}
else if(nums[mid] > target){
right = mid-1;
}
else{
result = mid;
left = mid+1;
}
}
return result;
}

private int searchLeft(int[] nums, int target){
int left = 0;
int right = nums.length-1;
int mid = 0;
int result = -1;

while(left <= right){
mid = (right-left+1)/2+left;
if(nums[mid] < target){
left = mid+1;
}
else if(nums[mid] > target){
right = mid-1;
}
else{
result = mid;
right = mid-1;
}
}
return result;
}
}

190. Reverse Bits

问题
Reverse bits of a given 32 bits unsigned integer.

Note:

  • Note that in some languages, such as Java, there is no unsigned integer type. In this case, both input and output will be given as a signed integer type. They should not affect your implementation, as the integer’s internal binary representation is the same, whether it is signed or unsigned.
  • In Java, the compiler represents the signed integers using 2’s complement notation. Therefore, in Example 2 above, the input represents the signed integer -3 and the output represents the signed integer -1073741825.

创建返回值ans。
每次向左移动一位ans,然后取n的尾数进行二进制或运算(相当于在尾部进行不进位的加和)。
然后将n向左移动一位。

  • 二进制下的或运算只保留两数间较大的位。(0011 | 0110 = 0111)
  • 二进制下的与运算只保留两数间皆为1的位。(0011 & 0110 = 0010)
  • 掩码(Mask)是在二进制下进行与运算。以1作为掩码时,前面的31为皆为0,因此进行与运算后只保留最后一位。

因此(n & 1)相当于n的二进制与000…001运算,只保留n的尾数。
然后(ans << 1)向左移动一位,用 | 操作将n的尾数加入ans。

1
2
3
4
5
6
7
8
9
10
11
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
int ans = 0;
for(int i = 0; i < 32; i++){
ans = (ans << 1) | (n & 1);
n >>= 1;
}
return ans;
}
}

169. Majority Element

问题
Given an array nums of size n, return the majority element.

The majority element is the element that appears more than ⌊n / 2⌋ times. You may assume that the majority element always exists in the array.

Boyer-Moore投票算法
基本思想:
众数的值为+1,非众数的值为-1。其加和作为投票值。
遍历整个数组,由于众数数量大于非众数,因此最后结果一定为正数。

设置count记录票数,遍历数组。
当count为0时,则将当前的数组设为众数。当之后的数字与其相等,则count+1,反之则-1。
遍历完成后返回当前的众数。

  • 根据以上规则,每次我们选择的众数,都是已遍历数组范围内出现最多次数的数值之一。

  • 由于给定的数组的众数超过半数,因此遍历到最后的众数,一定是整个数组中出现最多次的数值。

核心就是对拼消耗。
玩一个诸侯争霸的游戏,假设你方人口超过总人口一半以上,并且能保证每个人口出去干仗都能一对一同归于尽。最后还有人活下来的国家就是胜利。

那就大混战呗,最差所有人都联合起来对付你(对应你每次选择作为计数器的数都是众数),或者其他国家也会相互攻击(会选择其他数作为计数器的数),但是只要你们不要内斗,最后肯定你赢。

最后能剩下的必定是自己人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int majorityElement(int[] nums) {
int count = 0;
int major = 0;

for(int num : nums){
if(count == 0){
major = num;
}
if(major == num){
count++;
}
else{
count--;
}
}
return major;
}
}

遍历数组,并将各个数值出现的次数记录在哈希表中。
当出现的次数大于数组的一半,则该数值是众数。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int majorityElement(int[] nums) {
HashMap<Integer,Integer> map = new HashMap();
for(int num : nums){
map.put(num, map.getOrDefault(num,0)+1);
if(map.get(num) > nums.length/2){
return num;
}
}
return -1;
}
}

136. Single Number

Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.

You must implement a solution with a linear runtime complexity and use only constant extra space.

位运算,对所有数值做二进制异或运算。
两个同样的值异或运算会等于0,最后和与单独的数字相等。

1
2
3
4
5
6
7
8
9
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for(int num : nums){
ans = ans ^ num;
}
return ans;
}
}

排序,然后遍历数组,如果第i个值不等于第i+1个则返回。

1
2
3
4
5
6
7
8
9
10
11
class Solution {
public int singleNumber(int[] nums) {
Arrays.sort(nums);
for(int i = 0; i < nums.length-1; i+=2){
if(nums[i] != nums[i+1]){
return nums[i];
}
}
return nums[nums.length-1];
}
}

653. Two Sum IV - Input is a BST

问题
Given the root of a Binary Search Tree and a target number k, return true if there exist two elements in the BST such that their sum is equal to the given target.

DFS搜索,每次递归时检查HashSet中是否有当前节点的值。如没有则将目标值减去当前节点的值加入HashSet。如有则返回true。
递归左侧节点和右侧节点,并返回二者的或运算。

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
/**
* 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 {
HashSet<Integer> set;
public boolean findTarget(TreeNode root, int k) {
set = new HashSet();
return dfs(root,k);
}

private boolean dfs(TreeNode root, int k){
if(root == null){
return false;
}
if(set.contains(root.val)){
return true;
}
set.add(k - root.val);

return dfs(root.left,k) || dfs(root.right,k);
}
}

235. Lowest Common Ancestor of a BST

问题
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

DFS搜索,如果当前节点为null,则返回null。
如果当前节点小于p和q的值,则递归其左子节点。
反之递归其右子节点。
如果当前节点在p与q之间,则返回当前节点。
该节点是p与q的Lowest Common Ancestor。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/

class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null){
return null;
}
if(p.val < root.val && q.val < root.val){
return lowestCommonAncestor(root.left, p, q);
}
if(p.val > root.val && q.val > root.val){
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}

538. Convert BST to Greater Tree

问题
Given the root of a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus the sum of all keys greater than the original key in BST.

As a reminder, a binary search tree is a tree that satisfies these constraints:

  • 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.
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
/**
* 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;
* }
* }
*/

DFS搜索,设置一个成员变量记录上一个节点的值。
先递归右侧节点。
设置当前节点的值为自身的值加上temp中的值。
更新temp中的值,再递归左侧节点。


class Solution {
int temp;
public TreeNode convertBST(TreeNode root) {
temp = 0;
dfs(root);
return root;
}

private void dfs(TreeNode root){
if(root == null){
return;
}
dfs(root.right);
root.val += temp;
temp = root.val;
dfs(root.left);
}
}

669. Trim a Binary Search Tree

问题
Given the root of a binary search tree and the lowest and highest boundaries as low and high, trim the tree so that all its elements lies in [low, high]. Trimming the tree should not change the relative structure of the elements that will remain in the tree (i.e., any node’s descendant should remain a descendant). It can be proven that there is a unique answer.

Return the root of the trimmed binary search tree. Note that the root may change depending on the given bounds.

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
/**
* 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 TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null){
return null;
}
if(root.val < low){
return trimBST(root.right, low, high);
}
if(root.val > high){
return trimBST(root.left, low, high);
}

root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
}