前言
每天刷一刷,5050发。
LeetCode Top Interview Questions(0 - 50)
1 Tow Sum
找出数组中和为target的两个数的下标。你可以确保有且仅有一个解。
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
class Solution {
public int[] twoSum(int[] nums, int target) {
int res[] = new int[2];
HashMap<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i ++) {
//存入 (nums[i], 下标) 如果存在则说明匹配
if(map.get(target - nums[i]) != null) {
res[0] = map.get(target - nums[i]);
res[1] = i;
return res;
}
map.put(nums[i], i);
}
return res;
}
}
2 Add Two Numbers
将获得两个表示两个非负整数的非空链表。这些数字以相反的顺序存储,并且它们的每个节点都包含一个数字。将两个数字相加,并将其作为链表返回。您可能会假设两个数字除了数字0本身以外都不包含任何前导零。
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1 == null || l2 == null)return l1 == null ? l1 : l2;
ListNode res = new ListNode(0);
ListNode pre = res;;
int flag = 0;
int sum = 0;
while(l1 != null || l2 != null) {
//可能有长短不一的链表
if(l1 != null){sum += l1.val; l1 = l1.next;}
if(l2 != null){sum += l2.val; l2 = l2.next;}
sum += flag;
res.next = new ListNode(sum % 10);
flag = sum / 10;
sum = 0;
res = res.next;
}
//如果进位标记为一,则要多添加一个节点
if(flag == 1)
res.next = new ListNode(1);
return pre.next;
}
}
3 Longest Substring Without Repeating Characters
给定一个字符串,找到最长子字符串的长度而不重复字符。
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Longest Substring Without Repeating Characters
class Solution {
public int lengthOfLongestSubstring(String s) {
// 使用滑动窗口
int l = 0, r = -1;
// 设置还未移动最大的间距
int minIndex = 0;
int[] freq = new int[256];
for (int i = 0; i < freq.length; i++) {
freq[i] = 0;
}
while (l <= s.length() - 1) {
if (r + 1 < s.length() && freq[s.charAt(r + 1)] == 0) {
freq[s.charAt(++r)]++;
} else {
freq[s.charAt(l++)]--;
}
if (minIndex < r - l + 1)
minIndex = r - l + 1;
}
if (minIndex == s.length() + 1)
return 0;
return minIndex;
}
}
4 Median of Two Sorted Arrays(Hard)
找到两个排序数组的中位数
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
5 Longest Palindromic Substring
求最长子回文串
Example 1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
思路:中心回文算法
class Solution {
public String longestPalindrome(String s) {
if (s.length() <= 1) return s;
char[] ch = s.toCharArray();
int[] max = new int[2];
for (int i = 0; i < ch.length - 1; i++) {
dp(ch, i, i, max);
dp(ch, i, i+1, max);
}
return s.substring(max[0], max[0] + max[1]);
}
private void dp(char[] ch, int i, int j, int[] max) {
while (i >= 0 && j < ch.length && ch[i] == ch[j]) {
i--;
j++;
}
if (j - i - 1 > max[1]) {
max[0] = i + 1;
max[1] = j - i - 1;
}
}
}
6 Reverse Integer
反转数字 输入范围为 [Integer.MIN_VALUE ~ Integer.MAX_VALUE ] ,如果反转后益处,则返回0
Example 1:
Input: 123
Output: 321
Input: -123
Output: -321
class Solution {
public int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10;
x /= 10;
if (rev > Integer.MAX_VALUE/10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
if (rev < Integer.MIN_VALUE/10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
//唯一可能溢出的地方,前面需要判断是否溢出
rev = rev * 10 + pop;
}
return rev;
}
}
7 String to Integer (atoi)
实现一个字符串转int,但是有许多限制
Example 1:
Input: "42"
Output: 42
Input: " -42"
Output: -42
Explanation: The first non-whitespace character is '-', which is the minus sign.
Then take as many numerical digits as possible, which gets 42.
Input: "4193 with words"
Output: 4193
Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
Input: "words and 987"
Output: 0
Explanation: The first non-whitespace character is 'w', which is not a numerical
digit or a +/- sign. Therefore no valid conversion could be performed.
Input: "-91283472332"
Output: -2147483648
Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer.
Thefore INT_MIN is returned.
class Solution {
public int myAtoi(String str) {
str = str.trim();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
boolean isDigit = Character.isDigit(c);
if (i == 0) {
if (c != '+' && c != '-' && !isDigit) {
return 0;
} else {
sb.append(c);
continue;
}
}
if (isDigit) {
sb.append(c);
} else {
break;
}
}
String resultAsString = sb.toString();
if (resultAsString.isEmpty()) {
return 0;
}
char firstCharacter = resultAsString.charAt(0);
if (resultAsString.length() == 1 && !Character.isDigit(firstCharacter)) {
return 0;
}
try {
return Integer.parseInt(resultAsString);
} catch (NumberFormatException e) {
return firstCharacter == '-' ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
}
}
8 Regular Expression Matching(Hard)
正则表达式匹配
9 Container With Most Water
类似木桶原理,找到最大面积的两个坐标
思路:从数组两端收缩,保证底是最大值,之后为们收缩高度较低的板(因为这样才能确保面积可能扩大,因为面积受最小板的限制)
public class Solution {
public int maxArea(int[] height) {
int maxarea = 0, l = 0, r = height.length - 1;
while (l < r) {
maxarea = Math.max(maxarea, Math.min(height[l], height[r]) * (r - l));
if (height[l] < height[r])
l++;
else
r--;
}
return maxarea;
}
}
10 Roman to Integer
输入一个字符串,按照下列的规则转化成数字
Symbol Value I 1 V 5 X 10 L 50 C 100 D 500 M 1000
Example:
Input: "LVIII"
Output: 58
Explanation: L = 50, V= 5, III = 3.
class Solution {
public int romanToInt(String s) {
if(s == null || "".equals(s)) return 0;
int dic[] =new int[24];
dic[8] = 1;
dic[21] = 5;
dic[23] = 10;
dic[11] = 50;
dic[2] = 100;
dic[3] = 500;
dic[12] = 1000;
char[] chars = s.toCharArray();
//如果只有一个字符 则返回相应的值
if(chars.length == 1)return dic[chars[0] - 'A'];
int sum = 0;
for(int i = 0; i < chars.length; i ++) {
//如果前一个小于后一个,则sum加上后一个减去前一个
if(i + 1 < chars.length && dic[chars[i] - 'A'] < dic[chars[i + 1] - 'A']) {
sum += dic[chars[i + 1] - 'A'] - dic[chars[i] - 'A'];
//向后多移动一个位置
i ++;
} else {
sum += dic[chars[i] - 'A'];
}
}
return sum;
}
}
11 Longest Common Prefix
返回给定数组的最长子前缀,如果没有则返回空串
Example 1:
Input: ["flower","flow","flight"]
Output: "fl"
Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs == null || strs.length == 0)return "";
for(int i = 0; i < strs[0].length(); i ++) {
//使用第一个元素进行匹配
for(int j = 1; j < strs.length; j ++) {
//如果后面长度不够了,直接返回
if(strs[j].length() == i ||
strs[j].charAt(i) != strs[0].charAt(i)) {
return strs[0].substring(0, i);
}
}
}
//如果没有执行第二层循环,代表只有一个元素
return strs[0];
}
}
12 3Sum
找到3个数相加等于0 返回值,且结果不重复
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//首先如果要去重复值可以使用排序,重复的数字跳过
//已经排序后使用指针碰撞和第3个数匹配
List<List<Integer>> res = new ArrayList<>();
if(nums == null ||nums.length == 0)return res;
Arrays.sort(nums);
//遍历到只剩3个数为止
for(int i = 0; i < nums.length - 2; i ++) {
if(i > 0 && nums[i] == nums[i - 1])continue;
//找到后面的两个数字和为nums[i]
int l = i + 1, r = nums.length - 1;
while(l < r) {
if(nums[i] + nums[l] + nums[r] == 0) {
res.add(Arrays.asList(nums[i],nums[l],nums[r]));
while(l < r && nums[l] == nums[l + 1])l ++;
while(l < r && nums[r] == nums[r - 1])r --;
l ++;
r --;
} else if(nums[i] + nums[l] + nums[r] > 0)r --;
else l ++;
}
}
return res;
}
}
13 Letter Combinations of a Phone Number
给一个包含0 ~ 9的字符串,输出所有手机键盘上有可能组成的字符串
Letter Combinations of a Phone Number
//标准回溯算法
class Solution {
public List<String> letterCombinations(String digits) {
String[] let = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
List<String> res = new ArrayList<>();
if(digits == null || "".equals(digits))return res;
helper(res, new StringBuffer(""), 0, let, digits);
return res;
}
private void helper(List<String> res, StringBuffer sb, int index, String[] let, String digits) {
if(index > digits.length())return;
if(sb.length() == digits.length()) {
res.add(sb.toString());
return;
}
char[] chars = let[digits.charAt(index) - '0'].toCharArray();
for(int i = 0; i < chars.length; i ++) {
sb.append(chars[i]);
helper(res, sb, index + 1, let, digits);
sb.deleteCharAt(sb.length() - 1);
}
}
}
14 Remove Nth Node From End of List
删除链表的倒数第n个节点
Remove Nth Node From End of List
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head == null || n == 0)return head;
ListNode node = head;
ListNode pre = new ListNode(0);
pre.next = head;
while(n -- > 0) {
node = node.next;
}
while(node != null) {
node = node.next;
pre = pre.next;
}
if(pre.next == head)return pre.next.next;
pre.next = pre.next.next;
return head;
}
}
15 Valid Parentheses
匹配由{},[],()组成的字符串是否符合格式
Example:
Input: "()"
Output: true
Input: "()[]{}"
Output: true
Input: "(]"
Output: false
class Solution {
public boolean isValid(String s) {
if(s == null || s.length() == 1)return false;
Stack<Character> stack = new Stack<>();
for(int i = 0; i < s.length(); i ++) {
char c = s.charAt(i);
if(c == '(' || c == '{' || c == '[') {
stack.push(c);
continue;
}
else if(stack.isEmpty())return false;
else if(c == ')' && stack.pop() != '(')return false;
else if(c == ']' && stack.pop() != '[')return false;
else if(c == '}' && stack.pop() != '{')return false;
}
return stack.isEmpty();
}
}
16 Merge Two Sorted Lists
合并两个排序链表
Example:
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if(l1 == null || l2 == null)return l1 == null ? l2 : l1;
ListNode root;
if(l1 .val < l2.val) {
root = l1;
root.next = mergeTwoLists(l1.next, l2);
} else {
root = l2;
root.next = mergeTwoLists(l1, l2.next);
}
return root;
}
}
17 Generate Parentheses
给定n对括号,编写一个函数以生成格式正确的括号的所有组合。
Example:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
class Solution {
public List<String> generateParenthesis(int n) {
List<String> res = new ArrayList<>();
if(n == 0)return res;
helper(res, "", 0, 0, n);
return res;
}
private void helper(List<String> res, String s, int l, int r, int n) {
if(s.length() == 2 * n) {
res.add(s);
return;
}
if(l < n)
helper(res, s + "(", l + 1, r, n);
if(l > r)
helper(res, s + ")", l, r + 1, n);
}
}
18 Merge k Sorted Lists
合并k个排序链表
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return partition(lists, 0, lists.length - 1);
}
public ListNode partition(ListNode[] lists, int i, int j) {
if (i == j) {
return lists[i];
}
if (i < j) {
int mid = (i + j) / 2;
ListNode l1 = partition(lists, i, mid);
ListNode l2 = partition(lists, mid + 1, j);
return merge(l1, l2);
} else {
return null;
}
}
public ListNode merge(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
if (l1.val < l2.val) {
l1.next = merge(l1.next, l2);
return l1;
} else {
l2.next = merge(l2.next, l1);
return l2;
}
}
}
19 Remove Duplicates from Sorted Array
给定一个已排序的数组nums,就地删除重复项,以使每个元素仅出现一次并返回新的长度。
Example:
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length.
Remove Duplicates from Sorted Array
class Solution {
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0)return 0;
int len = 0;
//因为是排序的,所以把不重复的数字放到最前
for(int i = 1; i < nums.length; i ++) {
if(nums[len] != nums[i]) {
nums[++ len] = nums[i];
}
}
return len + 1;
}
}
20 Implement strStr()
找到needle第一次出现的位置
Example:
Input: haystack = "hello", needle = "ll"
Output: 2
class Solution {
public int strStr(String haystack, String needle) {
if (needle == null || needle.length() == 0) return 0;
int nLength = needle.length();
for (int i = 0; i < haystack.length() - nLength + 1; i ++) {
String possNeedle = haystack.substring(i, i + nLength);
if (possNeedle.equals(needle)) return i;
}
return -1;
}
}
21 Divide Two Integers
实现除法,不使用 /, *, %
class Solution {
public int divide(int dividend, int divisor) {
if (dividend == Integer.MIN_VALUE && divisor == -1) {
return Integer.MAX_VALUE;
}
boolean isNegtive = (dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0);
long up = Math.abs((long)dividend);
long down = Math.abs((long)divisor);
long res = 0;
while(down <= up) {
long count = 1;
long tmp = down;
while(tmp <= up) {
tmp <<= 1;
count <<= 1;
}
res += tmp == up ? count : count >> 1;
up -= (tmp >> 1);
}
return isNegtive ? (int)(0 - res) : (int)res;
}
}
22 Search in Rotated Sorted Array
在旋转数组中查找一个数,如果不存在返回-1。要求时间复杂度为O(logn)
Example:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Search in Rotated Sorted Array
class Solution {
public int search(int[] nums, int target) {
if(nums == null || nums.length == 0)return -1;
int l = 0, r = nums.length - 1;
while(l <= r) {
int mid = l - (l - r) / 2;
if(nums[mid] == target) return mid;
//67012345
else if (nums[l] > nums[mid]) {
if(target > nums[r] || target < nums[mid]) r = mid - 1;
else l = mid + 1;
}
//34567012
else {
if(target < nums[l] || target > nums[mid]) l = mid + 1;
else r = mid - 1;
}
}
return -1;
}
}
23 Find First and Last Position of Element in Sorted Array
在一个排序有重复数组中,找到target的起始和终止下标。时间复杂度要求O(logn),如果没有找到,返回[-1, -1]
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Find First and Last Position of Element in Sorted Array
class Solution {
// 返回目标数的开始和结束
public int[] searchRange(int[] nums, int target) {
int res[] = {-1, -1};
if (nums.length == 0)
return res;
int left = binarySearch(nums, target - 0.5);
int right = binarySearch(nums, target + 0.5);
if (right - left == 0)
return res;
res[0] = left;
res[1] = right - 1;
return res;
}
private int binarySearch(int[] arr, double target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] > target)
right = mid - 1;
else if (arr[mid] < target)
left = mid + 1;
}
return left;
}
}
24 Valid Sudoku
验证9 * 9数独的正确,每一行,每一列,每一个3 * 3 数组不能有重复
public boolean isValidSudoku(char[][] board) {
int[][][] freq = new int[3][9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int current = board[i][j] - '0';
int box = ++freq[0][(i / 3) * 3 + j / 3][current - 1];
int row = ++freq[1][i][current - 1];
int col = ++freq[2][j][current - 1];
if (box > 1 || row > 1 || col > 1) return false;
}
}
}
return true;
}
25 Count and Say
不知道题目啥意思
26 First Missing Positive
给定一个未排序的整数数组,找到最小的缺失正整数。时间复杂度要求O(n),空间复杂度O(1)
Example 1:
Input: [1,2,0]
Output: 3
Input: [3,4,-1,1]
Output: 2
Input: [7,8,9,11,12]
Output: 1
class Solution {
public int firstMissingPositive(int[] nums) {
for(int i = 0; i < nums.length; i ++) {
while(nums[i] > 0 && nums[i] <= nums.length) {
int tmp = nums[i];
if(tmp == nums[tmp - 1])break;//重复数据不叫唤
nums[i] = nums[tmp - 1];
nums[tmp - 1] = tmp;
}
}
for(int i = 0; i < nums.length; i ++) {
if(i + 1 != nums[i])
return i + 1;
}
return nums.length + 1;
}
}
27 Trapping Rain Water
给一个数组,假设如果下雨了,这个数组在xy坐标轴上会存多少水?
class Solution {
public int trap(int[] nums) {
if(nums == null || nums.length < 2)return 0;
int leftMax = 0, rightMax = 0;
int l = 0, r = nums.length - 1;
int res = 0;
//计算每个位置可以存多少水
while(l < r) {
if(nums[l] < nums[r]) {
if(nums[l] > leftMax)
leftMax = nums[l];
else
res += leftMax - nums[l];
l ++;
} else {
if(nums[r] > rightMax)
rightMax = nums[r] ;
else
res += rightMax - nums[r];
r --;
}
}
return res;
}
}
28 Wildcard Matching(Hard)
字符匹配
'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).
29 Permutations
给定一组不同的整数,返回所有可能的排列。
Example:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
class Solution {
List<List<Integer>> res;
boolean []used;
public List<List<Integer>> permute(int[] nums) {
if(nums == null || nums.length == 0)return new ArrayList<>();
res = new ArrayList<>();
used = new boolean[nums.length];
helper(nums, new ArrayList<>());
return res;
}
//回溯
private void helper(int[] nums, List<Integer> list) {
if(nums.length == list.size()) {
res.add(new ArrayList<>(list));
return;
}
for(int i = 0; i < nums.length; i ++) {
if(!used[i]) {
used[i] = true;
list.add(nums[i]);
helper(nums, list);
list.remove(list.size() - 1);
used[i] = false;
}
}
}
}
30 Rotate Image
您会得到一个表示图像的n x n 2D矩阵。将图像旋转90度(顺时针)。
Example 1:
Given input matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
rotate the input matrix in-place such that it becomes:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
class Solution {
public void rotate(int[][] matrix) {
if(matrix.length == 0)return;
//对角线互换
for(int i = 0; i < matrix.length; i ++){
for(int j = i; j < matrix[0].length; j ++){
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
//中竖线互换
for(int i = 0; i < matrix.length; i ++){
for(int j = 0; j < matrix[0].length / 2; j ++){
int temp = matrix[i][j];
matrix[i][j] = matrix[i][matrix[0].length - j - 1];
matrix[i][matrix[0].length - j - 1] = temp;
}
}
}
}
31 Group Anagrams
给定一个字符串数组,将相同字符分组在一起。
Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
思路:利用hashmap的特性,相同hash值的字符串分配到一起
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
if (strs.length == 0)
return new ArrayList<>();
List<List<String>> listAll = new ArrayList<>();
HashMap<String, List<String>> map = new HashMap<>();
for (String s : strs) {
String hash = hash(s);
if (!map.containsKey(hash))
map.put(hash, new ArrayList<String>());
map.get(hash).add(s);
}
listAll.addAll(map.values());
return listAll;
}
private String hash(String s) {
int arr[] = new int[26];
for (int i = 0; i < s.length(); i++) {
arr[s.charAt(i) - 'a']++;
}
return Arrays.toString(arr);
}
}
32 Pow(x, n)
实现pow函数
Example 1:
Input: 2.00000, 10
Output: 1024.00000
class Solution {
public double myPow(double x, int n) {
if(n == 0)return 1;
int pn = Math.abs(n);
double res = myPow(x, pn >> 1);
res *= res;
//防止溢出
if(res > Double.MAX_VALUE / res)return 0.0;
if((n & 1) == 1)res *= x;
if(n < 0)res = 1 / res;
return res;
}
}
33 Spiral Matrix
循环打印矩阵
class Solution {
public List < Integer > spiralOrder(int[][] matrix) {
List ans = new ArrayList();
if (matrix.length == 0)
return ans;
int r1 = 0, r2 = matrix.length - 1;
int c1 = 0, c2 = matrix[0].length - 1;
while (r1 <= r2 && c1 <= c2) {
for (int c = c1; c <= c2; c++) ans.add(matrix[r1][c]);
for (int r = r1 + 1; r <= r2; r++) ans.add(matrix[r][c2]);
if (r1 < r2 && c1 < c2) {
for (int c = c2 - 1; c > c1; c--) ans.add(matrix[r2][c]);
for (int r = r2; r > r1; r--) ans.add(matrix[r][c1]);
}
r1++;
r2--;
c1++;
c2--;
}
return ans;
}
}
34 Jump Game
给定一个非负整数数组,您最初位于该数组的第一个索引处。数组中的每个元素代表该位置的最大跳转长度。确定您是否能够达到最后一个索引。
Example 1:
Input: [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Input: [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum
jump length is 0, which makes it impossible to reach the last index.
思路:如果从该位置开始,我们可以到达最后一个索引,则我们将该数组中的位置称为“良好索引”。否则,该索引称为“不良索引”。然后问题减少到索引0是否为“良好索引”。
O(n^2)
public class Solution {
public boolean canJump(int[] nums) {
Index[] memo = new Index[nums.length];
for (int i = 0; i < memo.length; i++) {
memo[i] = Index.UNKNOWN;
}
memo[memo.length - 1] = Index.GOOD;
for (int i = nums.length - 2; i >= 0; i--) {
int furthestJump = Math.min(i + nums[i], nums.length - 1);
//如果能跳转到good节点,直接结束循环
for (int j = i + 1; j <= furthestJump; j++) {
if (memo[j] == Index.GOOD) {
memo[i] = Index.GOOD;
break;
}
}
}
return memo[0] == Index.GOOD;
}
}
O(n)
class Solution {
public boolean canJump(int[] nums) {
int len = nums.length;
int max = 0;
for(int i=0; i<=max; i++){
max = Math.max(max, i+nums[i]);
if(max >= len-1) return true;
}
return false;
}
}
O(n)
class Solution {
public boolean canJump(int[] nums) {
int lastValidIndex = nums.length - 1;
int i = nums.length - 1;
while (i >= 0) {
if (nums[i] + i >= lastValidIndex) {
lastValidIndex = i;
}
i--;
}
return lastValidIndex == 0;
}
}
35 Merge Intervals
给定间隔的集合,合并所有重叠的间隔。
Example:
Input: [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
class Solution {
private class IntervalComparator implements Comparator<int[]> {
@Override
public int compare(int[] a, int[] b) {
return a[0] - b[0];
}
}
public int[][] merge(int[][] intervals) {
Collections.sort(Arrays.asList(intervals), new IntervalComparator());
LinkedList<int[]> merged = new LinkedList<>();
for (int[] interval : intervals) {
if (merged.isEmpty() || merged.getLast()[1] < interval[0]) {
merged.add(interval);
} else {
merged.getLast()[1] = Math.max(merged.getLast()[1], interval[1]);
}
}
return merged.toArray(new int[merged.size()][]);
}
}
36 Unique Paths
机器人位于m x n网格的左上角(在下图中标记为“开始”)。机器人只能在任何时间点上下移动。机器人试图到达网格的右下角(在下图中标记为“完成”)。有多少可能的唯一路径?
class Solution {
public int uniquePaths(int m, int n) {
if(m == 0)return 0;
if(n == 0)return 1;
int res[][] = new int[m][n];
res[0][0] = 1;
for(int i = 0; i < m; i ++) {
for(int j = 0; j < n; j ++) {
//到这个位置的路径数 = 上一步往下走的路径数 + 上一步往右走的步数
if(i > 0)res[i][j] += res[i - 1][j];
if(j > 0)res[i][j] += res[i][j - 1];
}
}
return res[m - 1][n - 1];
}
}
37 Plus One
给一个整数数组,返回这个数组转化成int值 在加一的结果。
Example 1:
Input: [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.
class Solution {
public int[] plusOne(int[] digits) {
if (digits == null) {
return null;
}
for (int i = digits.length - 1; i >= 0; i--) {
if (digits[i] < 9) {
digits[i]++;
return digits;
} else {
digits[i] = 0;
}
}
// [9, 9, 9]
int[] result = new int[digits.length + 1];
result[0] = 1;
return result;
}
}
38 Sqrt(x)
实现Sqrt(x)
思路:使用二分搜索
class Solution {
public int mySqrt(int x) {
int l = 1, r = x;
while(l < r) {
int mid = l - (l - r) / 2 + 1;
if(mid > x / mid) r = mid - 1;
else l = mid;
}
return r;
}
}
39 Climbing Stairs
类似跳台阶,使用斐波那契数列实现
class Solution {
public int climbStairs(int n) {
if(n == 1)return 1;
if(n == 2)return 2;
int first = 1;
int secend = 2;
int res = 0;
for(int i = 2; i < n; i ++){
res = first + secend;
first = secend;
secend = res;
}
return res;
}
}
40 Set Matrix Zeroes
给定一个m x n矩阵,如果一个元素是0,设置它的行和列为0
Example:
Input:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
Output:
[
[1,0,1],
[0,0,0],
[1,0,1]
]
class Solution {
public void setZeroes(int[][] matrix) {
if(matrix == null || matrix.length == 0)return;
int m = matrix.length, n = matrix[0].length;
boolean flag = false;
//把0的标记都放到第一行第一列
for(int i = 0; i < m; i ++) {
if(!flag && matrix[i][0] == 0) {
//标记第一列是否要设置为0
flag = true;
}
for(int j = 1; j < n; j ++) {
if(matrix[i][j] == 0) {
matrix[0][j] = 0;
matrix[i][0] = 0;
}
}
}
for(int i = 1; i < m; i ++) {
for(int j = 1; j < n; j ++) {
if(matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
//判断第一列是否要置0
if(matrix[0][0] == 0) {
for(int i = 0; i < n; i ++) {
matrix[0][i] = 0;
}
}
//判断第一列是否要置0
if(flag) {
for(int i = 0; i < m; i ++) {
matrix[i][0] = 0;
}
}
}
}
41 Sort Colors
给定一个包含n个红色、白色或蓝色对象的数组,对它们进行排序,使相同颜色的对象相邻,颜色按红、白、蓝的顺序排列。这里,我们将使用整数0、1和2分别表示红色、白色和蓝色。
Example:
Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
class Solution {
public void sortColors(int[] nums) {
if(nums == null && nums.length == 0)return;
int l = 0, r = nums.length - 1;
for(int i = 0; i <= r; i ++) {
if(nums[i] == 1)continue;
if(nums[i] == 0) {
int tmp = nums[i];
nums[i] = nums[l];
nums[l] = tmp;
//和前面的换不管换0 和 1都要往前走 所以i不用减1,和前面换不可能换来2
l ++;
} else {
int tmp = nums[i];
nums[i] = nums[r];
nums[r] = tmp;
//因为和最后换可能换来0 或 2则 i --;
r --;
i --;
}
}
}
}
42 Minimum Window Substring
给定一个字符串S和一个字符串T,找出S中的最小窗口,该窗口将包含T中的所有字符。 复杂度O(n)
思路:使用滑动窗口
class Solution {
public String minWindow(String s, String t) {
if(s.length() < t.length())return "";
HashMap<Character,Integer> mapT = new HashMap<>();
HashMap<Character,Integer> mapS = new HashMap<>();
for(int i = 0 ; i < t.length() ; i ++) {
char c = t.charAt(i);
int count = mapT.getOrDefault(c, 0);
mapT.put(c, count + 1);
}
int formed = 0;
int requested = mapT.size();
int minL = s.length() + 1;
int left = 0,right = 0;
String result = "";
while(right < s.length()) {
char c = s.charAt(right);
int count = mapS.getOrDefault(c, 0);
mapS.put(c, count + 1);
if(mapT.containsKey(c) && mapT.get(c).intValue() == mapS.get(c).intValue())
formed++;
while(left <= right && formed == requested) {
if(minL > right - left + 1) {
result = s.substring(left, right + 1);
minL = right - left + 1;
}
mapS.put(s.charAt(left),mapS.get(s.charAt(left)) - 1);
if(mapT.containsKey(s.charAt(left)) && mapT.get(s.charAt(left)).intValue() > mapS.get(s.charAt(left)).intValue()) {
formed --;
}
left ++;
}
right++;
}
if(minL == s.length() + 1)
return "";
return result;
}
}
43 Subsets
输出素组的所有子集
class Solution {
List<List<Integer>> res;
public List<List<Integer>> subsets(int[] nums) {
res = new ArrayList<>();
if(nums == null || nums.length == 0) return res;
//找到长度为i的子集
for(int i = 0; i <= nums.length; i ++)
helper(new ArrayList<>(), nums, 0, i);
return res;
}
private void helper(List<Integer> list, int[]nums, int index, int k) {
if(list.size() == k) {
res.add(new ArrayList<>(list));
return;
}
for(int i = index; i < nums.length; i ++) {
list.add(nums[i]);
//避免重复 从i + 1之后添加
helper(list, nums, i + 1, k);
list.remove(list.size() - 1);
}
}
}
44 Word Search
给定一个2D板和一个单词,找出这个单词是否存在于网格中。
这个词可以由连续相邻单元格的字母构成,其中“相邻”单元格是水平或垂直相邻的单元格。同一个字母单元格不能使用多次。
Example:
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
Given word = "ABCCED", return true.
Given word = "SEE", return true.
Given word = "ABCB", return false.
class Solution {
boolean [][] used;//记录已经访问过的元素
public boolean exist(char[][] board, String word) {
if(board == null || board.length == 0)return false;
if(word == null || word.equals(""))return false;
int m = board.length, n = board[0].length;
used = new boolean[m][n];
for(int i = 0; i < m; i ++) {
for(int j = 0; j < n; j ++) {
//匹配第一个字符
if(board[i][j] == word.charAt(0) && helper(board, word, i, j, 0))
return true;
}
}
return false;
}
private boolean helper(char[][]board, String word, int x, int y, int len) {
if(x < 0 || x > board.length - 1 || y < 0 || y > board[0].length - 1 || used[x][y]
|| len > word.length() || board[x][y] != word.charAt(len)) return false;
if(len + 1 == word.length()) {
return true;
}
used[x][y] = true;
//如果有一条路径找到直接返回
if(helper(board, word, x + 1, y, len + 1)
|| helper(board, word, x, y + 1, len + 1)
|| helper(board, word, x - 1, y, len + 1)
|| helper(board, word, x, y - 1, len + 1))
return true;
used[x][y] = false;
return false;
}
}
45 Largest Rectangle in Histogram
给定n个非负整数表示直方图的条高,其中每个条的宽度为1,在直方图中找到最大矩形的区域。
Largest Rectangle in Histogram
class Solution {
public int largestRectangleArea(int[] heights) {
if(heights == null || heights.length == 0)return 0;
int []lessFromLeft = new int[heights.length];//存储大于等于当前长度的最小坐标
int []lessFromRight = new int[heights.length];//存储大于等于当前长度的最大坐标
lessFromRight[heights.length - 1] = heights.length;
lessFromLeft[0] = -1;
for(int i = 1; i < heights.length; i ++) {
int p = i - 1;
while(p >= 0 && heights[p] >= heights[i]) {
p = lessFromLeft[p];
}
lessFromLeft[i] = p;
}
for(int i = heights.length - 2; i >= 0; i --) {
int p = i + 1;
while(p < heights.length && heights[p] >= heights[i]) {
p = lessFromRight[p];
}
lessFromRight[i] = p;
}
int max = 0;
for(int i = 0; i < heights.length; i ++) {
max = Math.max(max, heights[i] * (lessFromRight[i] - lessFromLeft[i] - 1));
}
return max;
}
}
46 Merge Sorted Array
给定两个排序整数数组nums1和nums2,将nums2合并为一个排序数组nums1。
Example:
Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
思路:归并排序最后一步合并
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
m -= 1;
n -= 1;
int l = nums1.length - 1;
while(m >= 0 && n >= 0){
nums1[l --] = nums1[m] > nums2[n] ? nums1[m --] : nums2[n --];
}
while(n >= 0)
nums1[l --] = nums2[n --];
}
}
47 Decode Ways
使用以下映射将包含A-Z字母的邮件编码为数字:
“A”->1
“B”->2
…
“Z”->26
给定一个只包含数字的非空字符串,确定解码该字符串的方法总数。
Example:
Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).
思路:类似青蛙跳台阶的斐波那契数列。只是f(n - 2)需要满足条件
class Solution {
public int numDecodings(String s) {
if(s.length() == 0)return 0;
int []dp = new int[s.length() + 1];
dp[0] = 1;
dp[1] = s.charAt(0) == '0' ? 0 : 1;
for(int i = 2; i <= s.length(); i ++) {
int f = Integer.valueOf(s.substring(i - 1, i));
int se = Integer.valueOf(s.substring(i - 2,i));
if(f >= 1 && f <= 9)
dp[i] += dp[i - 1];
if(se >= 10 && se <= 26)
dp[i] += dp[i - 2];
}
return dp[s.length()];
}
}
48 Binary Tree Inorder Traversal
返回二叉树的中序排序
- 1 递归
class Solution {
private List<Integer> res;
public List<Integer> inorderTraversal(TreeNode root) {
res = new ArrayList<>();
if(root == null)return res;
helper(root);
return res;
}
private void helper(TreeNode node) {
if(node != null) {
helper(node.left);
res.add(node.val);
helper(node.right);
}
}
}
- 2 非递归
class Solution {
List<Integer> res;
public List<Integer> inorderTraversal(TreeNode root) {
res = new ArrayList<>();
if(root == null)return res;
Stack<TreeNode> stack = new Stack<>();
while(!stack.isEmpty() || root != null) {
while(root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
}
49 Validate Binary Search Tree
验证一棵树是否是二分搜素树
思路:二分搜索树的中序遍历是递增的,所以使用非递归方式遍历判断是否是递增即可
class Solution {
public boolean isValidBST(TreeNode root) {
if(root == null)return true;
Long temp = Long.MIN_VALUE;
Stack<TreeNode> stack = new Stack<>();
while(root != null || !stack.isEmpty()){
while(root != null){
stack.push(root);
root = root.left;
}
root = stack.pop();
if(temp >= root.val)
return false;
else
temp = (long)root.val;
root = root.right;
}
return true;
}
}
50 Symmetric Tree
判断一棵树是否是对称的
1
/ \
2 2
/ \ / \
3 4 4 3
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null)return true;
return isSymmetric(root.left, root.right);
}
public boolean isSymmetric(TreeNode node1, TreeNode node2) {
if(node1 == null)return node2 == null;
if(node2 == null)return node1 == null;
return node1.val == node2.val && isSymmetric(node1.left, node2.right) && isSymmetric(node2.left, node1.right);
}
}