前言
每天刷一刷,5050发。
LeetCode Top Interview Questions(50 - 100)
51 Binary Tree Level Order Traversal
二叉树的层序遍历
For example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return
[
[3],
[9,20],
[15,7]
]
Binary Tree Level Order Traversal
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null)return new ArrayList<>();
Queue<TreeNode> q = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
q.add(root);
//层序遍历使用队列 现进先出
while(!q.isEmpty()){
int size = q.size();
List<Integer> t = new ArrayList<>();
for(int i = 0; i < size; i++) {
TreeNode node = q.poll();
t.add(node.val);
if(node.left != null)
q.add(node.left);
if(node.right != null)
q.add(node.right);
}
res.add(t);
}
return res;
}
}
52 Binary Tree Zigzag Level Order Traversal
二叉树之字型遍历
Binary Tree Zigzag Level Order Traversal
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.add(root);
while (!stack1.isEmpty() || !stack2.isEmpty()) {
ArrayList<Integer> list = new ArrayList<>();
if (!stack1.isEmpty()) {
while (!stack1.isEmpty()) {
TreeNode node = stack1.pop();
list.add(node.val);
if (node.left != null) stack2.add(node.left);
if (node.right != null) stack2.add(node.right);
}
res.add(new ArrayList<>(list));
} else {
while (!stack2.isEmpty()) {
TreeNode node = stack2.pop();
list.add(node.val);
if (node.right != null) stack1.add(node.right);
if (node.left != null) stack1.add(node.left);
}
res.add(new ArrayList<>(list));
}
}
return res;
}
}
53 Maximum Depth of Binary Tree
二叉树的深度
class Solution {
public int maxDepth(TreeNode root) {
if(root == null)
return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
54 Construct Binary Tree from Preorder and Inorder Traversa
使用前序排序和中序排序的值构造二叉树
Construct Binary Tree from Preorder and Inorder Traversal
public class BuildTree {
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
int preL = pre.length, inL = in.length;
if (pre == null || in == null || preL != inL)
throw new IllegalArgumentException();
return build(pre, 0, preL - 1, in, 0, inL - 1);
}
//{1,2,4,7,3,5,6,8} 前序遍历 1 是根 (第一个元素)
//{4,7,2,1,5,3,8,6} {4,7,2 (左孩子)1(右孩子) 5,3,8,6} 进行递归
private TreeNode build(int[] pre, int ps, int pe, int[] in, int is, int ie) {
if (ps > pe || is > ie) return null;
TreeNode root = new TreeNode(pre[ps]);
for (int i = is; i <= ie; i++) {
if (pre[ps] == in[i]) {
root.left = build(pre, ps + 1, i - is + ps, in, is, i - 1);
root.right = build(pre, i - is + ps + 1, pe, in, i + 1, ie );
break;
}
}
return root;
}
}
55 Convert Sorted Array to Binary Search Tree
给定一个按升序排序元素的数组,将其转换为高度平衡的BST。对于这个问题,高度平衡二叉树被定义为每个节点的两个子树的深度相差不超过1的二叉树。
Convert Sorted Array to Binary Search Tree
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
if(nums.length == 0)return null;
return helper(nums,0, nums.length - 1);
}
//每次取中值 构建左右子树
private TreeNode helper(int[] nums,int l, int r){
if(l > r)return null;
if(l == r)return new TreeNode(nums[l]);
int mid = (l + r) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = helper(nums, l , mid - 1);
root.right = helper(nums, mid + 1 , r);
return root;
}
}
56 Populating Next Right Pointers in Each Node
你得到了一个完美的二叉树,所有的叶子都在同一个层次上,并且每个父母都有两个孩子。二叉树有以下内容填充每个下一个指针以指向其下一个右节点。如果没有下一个右节点,则下一个指针应设置为空。最初,所有下一个指针都设置为空。
Populating Next Right Pointers in Each Node
class Solution {
public Node connect(Node root) {
if(root == null) return null;
Queue<Node> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()) {
int size = q.size();
while(size -- > 0) {
Node node = q.remove();
if(node.left != null)q.add(node.left);
if(node.right != null)q.add(node.right);
if(size != 0) {
node.next = q.peek();
}
}
}
return root;
}
}
57 Pascal’s Triangle
打印三角形
Example:
Input: 5
Output:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> res = new ArrayList<>();
if(numRows < 1)return res;
List<Integer> list = new ArrayList<>();
for(int i = 0; i < numRows; i ++) {
list.add(0, 1);
for(int j = 1; j < i; j ++) {
list.set(j, res.get(i - 1).get(j - 1) + res.get(i - 1).get(j));
}
res.add(new ArrayList<>(list));
}
return res;
}
}
58 Best Time to Buy and Sell Stock
股票的最佳买卖时间,次数限制1。
Example:
Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Not 7-1 = 6, as selling price needs to be larger than buying price.
Best Time to Buy and Sell Stock
class Solution {
//dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + price[i])
//dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - price[i]);
public int maxProfit(int[] prices) {
int i_k_0 = 0;
int i_k_1 = Integer.MIN_VALUE;
for(int i = 0; i < prices.length; i ++) {
i_k_0 = Math.max(i_k_0, i_k_1 + prices[i]);
i_k_1 = Math.max(i_k_1, - prices[i]);
}
return i_k_0;
}
}
59 Best Time to Buy and Sell Stock II
股票的最佳买卖时间,不限制买卖次数。
Best Time to Buy and Sell Stock II
class Solution {
//dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + price[i])
//dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - price[i]);
public int maxProfit(int[] prices) {
int i_k_0 = 0;
int i_k_1 = Integer.MIN_VALUE;
for(int i = 0; i < prices.length; i ++) {
int tmp = i_k_0;
i_k_0 = Math.max(i_k_0, i_k_1 + prices[i]);
i_k_1 = Math.max(i_k_1, tmp - prices[i]);
}
return i_k_0;
}
}
60 Binary Tree Maximum Path Sum
给定一个非空的二叉树,求最大路径和。对于此问题,路径定义为沿父子连接从某个起始节点到树中任何节点的任意节点序列。路径必须至少包含一个节点,并且不需要经过根节点。
Example:
Input: [1,2,3]
1
/ \
2 3
Output: 6
Input: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
Output: 42
class Solution {
public int maxPathSum(TreeNode root) {
if(root == null) return 0;
findMaxPathSum(root);
return max;
}
int max = Integer.MIN_VALUE;
private int findMaxPathSum(TreeNode node) {
if(node == null)return 0;
//如果左右节点的值小于0 则不加
int left = Math.max(0, findMaxPathSum(node.left));
int right = Math.max(0, findMaxPathSum(node.right));
max = Math.max(max , node.val + left + right);
//返回经过node节点的最大值
return node.val + Math.max(left , right);
}
}
61 Valid Palindrome
给定字符串,请仅考虑字母数字字符并忽略大小写,从而确定它是否是回文。
Example 1:
Input: "A man, a plan, a canal: Panama"
Output: true
Example 2:
Input: "race a car"
Output: false
class Solution {
public boolean isPalindrome(String s) {
s = s.toLowerCase(); // convert all to lower cases.
s = s.replaceAll("[^a-z^0-9]+", ""); // remove all non-digital and non-letter.
int len = s.length();
for (int i = 0; i < len; i++) {
if (s.charAt(i) != s.charAt(len - i - 1)) {
return false;
}
}
return true;
}
}
62 Word Ladder
给定两个单词(beginWord和endWord)以及字典的单词列表,找到从beginWord到endWord的最短转换序列的长度,例如:一次只能更改一个字母。每个转换的单词都必须存在于单词列表中。
Example 1:
Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
Output: 5
Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.
Example 2:
Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Output: 0
Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
63 Longest Consecutive Sequence
给定一个未排序的整数数组,请找出最长的连续元素序列的长度。您的算法应以O(n)复杂度运行。
Example:
Input: [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> num_set = new HashSet<Integer>();
for (int num : nums) {
num_set.add(num);
}
//最大长度
int longestStreak = 0;
for (int num : num_set) {
//找到每个序列的最小值开始计算
if (!num_set.contains(num - 1)) {
int currentNum = num;//当前数字
int currentStreak = 1;//当前的长度
while (num_set.contains(currentNum + 1)) {
currentNum += 1;
currentStreak += 1;
}
longestStreak = Math.max(longestStreak, currentStreak);
}
}
return longestStreak;
}
}
64 Surrounded Regions
给定一个包含“ X”和“ O”(字母O)的2D板,捕获被“ X”包围的所有区域。
Example:
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
思路:反向填充
class Solution {
boolean isFlag[][];
int m, n;
int d[][] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
private boolean isArea(int x, int y) {
return x >= 0 && y >= 0 && x < m && y < n;
}
private void flag(char[][] board, int x, int y, boolean flag) {
if (flag) board[x][y] = 'X';
isFlag[x][y] = true;
for (int i = 0; i < 4; i++) {
int newX = x + d[i][0];
int newY = y + d[i][1];
if (isArea(newX, newY) && board[newX][newY] == 'O' && !isFlag[newX][newY])
flag(board, newX, newY, flag);
}
}
public void solve(char[][] board) {
m = board.length;
if (m == 0) return;
n = board[0].length;
isFlag = new boolean[m][n];
for (int j = 0; j < n; j++) {
if (board[0][j] == 'O') {
flag(board, 0, j, false);
}
if (board[m - 1][j] == 'O') {
flag(board, m - 1, j, false);
}
}
for (int i = 0; i < m; i++) {
if (board[i][0] == 'O') {
flag(board, i, 0, false);
}
if (board[i][n - 1] == 'O') {
flag(board, i, n - 1, false);
}
}
for (int i = 1; i < m; i++)
for (int j = 1; j < n; j++)
if (board[i][j] == 'O' && !isFlag[i][j]) {
flag(board, i, j, true);
}
}
}
65 Palindrome Partitioning
给定字符串s,分区s,使得分区的每个子字符串都是回文。返回s的所有可能的回文分区。
Example:
Input: "aab"
Output:
[
["aa","b"],
["a","a","b"]
]
public List<List<String>> partition(String s) {
int len = s.length();
boolean[][] dp = new boolean[len][len];
List<List<String>> r = new ArrayList<>();
dfs(r, s, 0, new ArrayList<>(), dp);
return r;
}
void dfs(List<List<String>> r, String s, int start, List<String> path, boolean[][] dp) {
int len = s.length();
if (start >= len) r.add(new ArrayList<>(path));
for (int i = start; i < len; i++) {
// i
// abca ... //a == a, ok
if (s.charAt(i) != s.charAt(start)) continue;
// i
// abca ... //b != c continue
if (i - 1 > start + 1 && !dp[start + 1][i - 1]) continue;
dp[start][i] = true;
path.add(s.substring(start, i + 1));
dfs(r, s, i + 1, path, dp);
path.remove(path.size() - 1);
}
}
66 Gas Station
沿循环路线有N个加油站,其中加气站i的气体量为gas [i]。您有一辆带无限油箱的汽车,从第i站到下一个(i + 1)的行车成本为[i]。您可以从其中一个加油站的空罐开始旅程。如果您可以沿顺时针方向绕过回路一次,则返回起始加油站的索引,否则返回-1。
Example:
Input:
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]
Output: 3
Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int n = gas.length;
if(n==0) return -1;
int start = 0;
int residual = 0;
int sum = 0;
for(int i = 0; i < n; i++){
sum += gas[i] - cost[i];
residual += gas[i] - cost[i];
//如果剩余的小于 到下一站到距离,则说明起始点一定不是这站和之前到站
if(residual < 0){
start = i + 1;
residual = 0;
}
}
//sum为跑完之后剩下的油,如果>=0,则说明可以跑完 返回start
//不能跑完返回-1
return sum >= 0 ? start : -1;
}
}
67 Single Number
给定一个非空的整数数组,每个元素出现两次,除了一个。找到那一个。
思路:0 ^ n = n. n ^ n = 0;
class Solution {
public int singleNumber(int[] nums) {
if(nums.length == 0)return 0;
int res = nums[0];
for(int i = 1; i < nums.length; i ++) {
res ^= nums[i];
}
return res;
}
}
68 Copy List with Random Pointer
复制复杂链表,这个链表不仅有指向下一个节点的指针,还有一个指向随机节点的指针
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
Node node = head;
//在原链表的每个节点后面添加一个相同节点
while (node != null) {
Node nNode = new Node(node.val);
nNode.next = node.next;
node.next = nNode;
node = nNode.next;
}
//复制随机节点
node = head;
while (node != null) {
if(node.random != null)
node.next.random = node.random.next;
node = node.next.next;
}
//分裂两个链表
Node pre = new Node(0);
Node npre = new Node(0);
pre.next = head;
npre.next = head.next;
node = head;
Node nNode = head.next;
while (node != null) {
node.next = nNode.next;
node = node.next;
if(node == null)break;
nNode.next = node.next;
nNode = nNode.next;
}
// while(head != null) {
// System.out.print("[" + head.val + "," +
// (head.random == null ? "null" : head.random.val) + " ]");
// head = head.next;
// }
return npre.next;
}
}
69 Word Break
给定一个非空字符串s和包含非空单词列表的字典wordDict,请确定s是否可以分段为一个或多个字典单词的以空格分隔的序列。
class Solution {
HashMap<String, Boolean> map = new HashMap<>();
public boolean wordBreak(String s, List<String> wordDict) {
if (s == null || s.isEmpty()) return true;
if (map.containsKey(s)) return map.get(s);
for (String w : wordDict) {
int val = s.indexOf(w);
if (val != -1) {
//剔除符合条件的字符串
String temp = s.substring(0, val);
String temp1 = s.substring(val + w.length(), s.length());
if (wordBreak(temp, wordDict) && wordBreak(temp1, wordDict)) {
map.put(s, true);
return true;
}
}
}
map.put(s, false);
return false;
}
}
70 Word Break II
给定一个非空字符串s和包含非空单词列表的字典wordDict,请确定s是否可以分段为一个或多个字典单词的以空格分隔的序列。输出可能的分段信息。
71 Linked List Cycle
判断链表中是否存在环
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null)return false;
ListNode low = head;
ListNode fast = head;
while(fast != null && fast.next != null) {
low = low.next;
fast = fast.next.next;
if(low == fast)return true;
}
return false;
}
}
72 LRU Cache
实现LRU算法
class LRUCache {
class Node {
int key;
int value;
Node next;
Node pre;
public Node(){}
public Node(int key, int value) {
this.key = key;
this.value = value;
next = null;
pre = null;
}
}
Node head;
Node tail;
int capacity;
HashMap<Integer, Node> map;
public LRUCache(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
map = new HashMap<>();
head = new Node();
tail = new Node();
//初始化头尾指针
tail.pre = head;
head.next = tail;
}
public int get(int key) {
if (!map.containsKey(key)) return -1;
return moveHead(key).value;
}
public Node moveHead(int key) {
Node node = map.get(key);
if(node.pre == head) return node;
//删除当前位置节点
Node preNode = node.pre;
preNode.next = node.next;
preNode.next.pre = preNode;
//设置到头节点
putHead(node);
return node;
}
private Node putHead(Node node) {
node.next = head.next;
head.next = node;
node.pre = head;
node.next.pre = node;
return node;
}
public void put(int key, int value) {
if(map.containsKey(key)) {
//将节点放到第一个
//修改新值
moveHead(key).value = value;
} else {
Node node = putHead(new Node(key, value));
map.put(key, node);
}
if (map.size() > capacity) {
removeTail(tail.pre);
}
}
private void removeTail(Node node) {
tail.pre = tail.pre.pre;
tail.pre.next = tail;
map.remove(node.key);
}
}
73 Sort List
使用恒定的空间复杂度,以O(n log n)时间对链表进行排序。
class Solution {
public ListNode sortList(ListNode head) {
if(head == null)return null;
ListNode dummyMin = new ListNode(1);
ListNode dummyMax = new ListNode(1);
ListNode preMin = dummyMin;
ListNode preMax = dummyMax;
ListNode pre;
pre = head;
ListNode node = head.next;
while(node != null) {
if(node.val > head.val) {
preMax.next = node;
preMax = preMax.next;
} else if(node.val < head.val) {
preMin.next = node;
preMin = preMin.next;
} else {
pre.next = node;
pre = pre.next;
}
node = node.next;
}
preMax.next = preMin.next = pre.next = null;
dummyMin.next = sortList(dummyMin.next);
dummyMax.next = sortList(dummyMax.next);
ListNode minListNode = dummyMin;
while(minListNode.next != null) {
minListNode = minListNode.next;
}
minListNode.next = head;
pre.next = dummyMax.next;
return dummyMin.next;
}
}
74 Max Points on a Line(Hard)
给定2D平面上的n个点,求出同一直线上的最大点数。
75 Evaluate Reverse Polish Notation
用反向波兰语表示法计算算术表达式的值。有效的运算符为+,-,*,/。每个操作数可以是整数或另一个表达式。注意:两个整数之间的除法应截断为零。给定的RPN表达式始终有效。这意味着表达式将始终求结果,并且不会被零运算除以。
Example 1:
Input: ["2", "1", "+", "3", "*"]
Output: 9
Explanation: ((2 + 1) * 3) = 9
Example 2:
Input: ["4", "13", "5", "/", "+"]
Output: 6
Explanation: (4 + (13 / 5)) = 6
Evaluate Reverse Polish Notation
76 Maximum Product Subarray
给定一个整数数组nums,在具有最大乘积的数组(至少包含一个数字)中找到连续的子数组。
class Solution {
public int maxProduct(int[] nums) {
if(nums == null || nums.length < 1)return 0;
int max = nums[0];
int min = nums[0];
int res = max;
for(int i = 1; i < nums.length; i ++) {
if(nums[i] < 0) {
int tmp = max;
max = min;
min = tmp;
}
max = Math.max(nums[i], nums[i] * max);
min = Math.min(nums[i], nums[i] * min);
res = Math.max(max, res);
}
return res;
}
}
77 Min Stack
设计一个堆栈,该堆栈支持在固定时间内推送,弹出,顶出和检索最小元素。push(x)-将元素x推入堆栈pop()-删除堆栈顶部的元素。top()-获取顶部元素。getMin()-检索堆栈中的最小元素。
class MinStack {
/** initialize your data structure here. */
int min = Integer.MAX_VALUE;
Stack<Integer> stack;
public MinStack() {
stack = new Stack<Integer>();
}
public void push(int x) {
if(x <= min) {
stack.push(min);
min = x;
}
stack.push(x);
}
public void pop() {
if(stack.pop() == min) {
min = stack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
}
78 Intersection of Two Linked Lists
返回两个链表的交点
Intersection of Two Linked Lists
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null)
return null;
ListNode a = headA;
ListNode b = headB;
while(a != b){
a = a == null ? headB : a.next;
b = b == null ? headA : b.next;
}
return a;
}
}
79 Find Peak Element
峰值元素是大于其相邻元素的元素。给定一个输入数组nums,其中nums [i]≠nums [i + 1],找到一个峰值元素并返回其索引。该数组可能包含多个峰,在这种情况下,将索引返回到任何一个峰都可以。
Example 1:
Input: nums = [1,2,3,1]
Output: 2
Explanation: 3 is a peak element and your function should return the index number 2.
Example 2:
Input: nums = [1,2,1,3,5,6,4]
Output: 1 or 5
Explanation: Your function can return either index number 1 where the peak element is 2,
or index number 5 where the peak element is 6.
class Solution {
public int findPeakElement(int[] nums) {
int l = 0, r = nums.length - 1;
while(l < r) {
int mid = l - (l - r) / 2;
if(nums[mid] > nums[mid + 1])
r = mid;
else
l = mid + 1;
}
return l;
}
}
80 Missing Ranges(VIP专享)
81 Fraction to Recurring Decimal
给定两个表示分数的分子和分母的整数,以字符串格式返回分数。如果小数部分是重复的,请将重复的部分括在括号中。
Example 1:
Input: numerator = 1, denominator = 2
Output: "0.5"
Example 2:
Input: numerator = 2, denominator = 1
Output: "2"
Example 3:
Input: numerator = 2, denominator = 3
Output: "0.(6)"
public String fractionToDecimal(int numerator, int denominator) {
if (denominator == 0) return "";
StringBuilder str = new StringBuilder();
HashMap<Long, Integer> map = new HashMap<Long, Integer>();
if (numerator < 0 && denominator > 0 || numerator > 0 && denominator < 0) {
str.append('-');
}
long num = Math.abs((long) numerator);
long den = Math.abs((long) denominator);
long n = num / den;
long reminder = num % den;
str.append(n);
if (reminder == 0) return str.toString();
else str.append('.');
while (!map.containsKey(reminder)) {
map.put(reminder, str.length());
n = reminder * 10 / den;
reminder = reminder * 10 % den;
if (reminder != 0 || reminder == 0 && !map.containsKey(reminder)) {
str.append(n);
}
}
if (reminder != 0) {
str.insert(map.get(reminder), "(");
str.append(')');
}
return str.toString();
}
82 Majority Element
给定大小为n的数组,找到多数元素。多数元素是出现超过⌊n / 2倍的元素。您可以假定数组为非空,并且多数元素始终存在于数组中
class Solution {
public int majorityElement(int[] nums) {
int count = 0;
Integer candidate = null;
for (int num : nums) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1;
}
return candidate;
}
}
83 Excel Sheet Column Number
给定列标题(如Excel工作表中所示),返回其对应的列号。例如:
For example:
A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ...
class Solution {
public int titleToNumber(String s) {
int sum = 0;
for(int i = 0; i < s.length(); i ++){
sum = sum * 26 + (s.charAt(i) - 'A' + 1);
}
return sum;
}
}
84 Factorial Trailing Zeroes
给定整数n,返回n!中尾随零的数目。
class Solution {
public int trailingZeroes(int n) {
return n < 5 ? 0 : n / 5 + trailingZeroes(n / 5);
}
}
85 Largest Number
给定一个非负整数列表,将它们排列为最大的数字。
Example 1:
Input: [10,2]
Output: "210"
Example 2:
Input: [3,30,34,5,9]
Output: "9534330"
class Solution {
public String largestNumber(int[] numbers) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < numbers.length; i++) {
list.add(numbers[i]);
}
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
String s1 = o1 + "" + o2;
String s2 = o2 + "" + o1;
return s2.compareTo(s1);
}
});
if(list.get(0) == 0)return "0";
String res = "";
for (int i = 0; i < list.size(); i++) {
res += list.get(i);
}
return res;
}
}
86 Rotate Array
给定一个数组,将数组向右旋转k步,其中k为非负数。
Example:
Input: [1,2,3,4,5,6,7] and k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0 || k <= 0)return;
int n = k % nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, n - 1);
reverse(nums, n, nums.length - 1);
}
private void reverse(int[] nums,int l, int r) {
while(l < r) {
int tmp = nums[l];
nums[l] = nums[r];
nums[r] = tmp;
l ++;
r --;
}
}
}
87 Reverse Bits
给定的32位无符号整数的反向位。
Example:
Input: 00000010100101000001111010011100
Output: 00111001011110000010100101000000
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 which its binary representation is 00111001011110000010100101000000.
public class Solution {
// you need treat n as an unsigned value
public int reverseBits(int n) {
int res = 0;
for(int i = 0; i < 32; i ++){
res <<= 1;
res |= n & 1;
n >>= 1;
}
return res;
}
}
88 Populating Next Right Pointers in Each Node
您将得到一棵完美的二叉树,其中所有叶子都在同一水平上,每个父级都有两个孩子。二进制树具有以下定义:
struct Node { int val; Node *left; Node *right; Node *next; }
填充每个下一个指针以指向其下一个右节点。如果没有下一个右节点,则下一个指针应设置为NULL。最初,所有下一个指针都设置为NULL。
Populating Next Right Pointers in Each Node
class Solution {
public Node connect(Node root) {
if (root == null) return null;
if (root.left != null) {
root.left.next = root.right;
root.right.next = root.next == null ? null : root.next.left;
}
connect(root.left);
connect(root.right);
return root;
}
}
89 Number of 1 Bits
编写一个函数,该函数采用无符号整数并返回其具有的’1’位的数量(也称为汉明权重)
Example 1:
Input: 00000000000000000000000000001011
Output: 3
Explanation: The input binary string 00000000000000000000000000001011 has a total of three '1' bits.
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count = 0;
while(n != 0) {
n &= n - 1;
count ++;
}
return count;
}
}
90 House Robber
您是计划在街道上抢房屋的专业强盗。每栋房屋都藏有一定数量的金钱,阻止您抢劫每座房屋的唯一限制是相邻房屋都已连接了安全系统,如果在同一晚闯入两栋相邻房屋,它将自动与警方联系。给定代表每个房屋的金额的非负整数列表,请确定您今晚可在不提醒警察的情况下抢走的最大金额。
Example 1:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
- 1 记忆化搜索
class Solution {
int memo[];
public int rob(int[] nums) {
if(nums == null || nums.length == 0)return 0;
memo = new int[nums.length];
Arrays.fill(memo, -1);
return tryRob(nums, 0);
}
public int tryRob(int[] nums, int index) {
if(index >= nums.length)return 0;
if(memo[index] != -1)return memo[index];
int res = 0;
for(int i = index; i < nums.length; i ++) {
//偷和不偷两个状态
res = Math.max(res, nums[i] + tryRob(nums, i + 2));
}
memo[index] = res;
return res;
}
}
- 2 动态规划
class Solution {
public int rob(int[] nums) {
if(nums == null || nums.length == 0)return 0;
memo = new int[nums.length];
memo[nums.length - 1] = nums[nums.length - 1];
for(int i = nums.length -2; i >= 0; i --) {
for(int j = i; j < nums.length; j ++) {
memo[i] = Math.max(memo[i], nums[j] +
(j + 2 < nums.length ? memo[j + 2] : 0));
}
}
return memo[0];
}
}
91 Number of Islands
给定二维地图“ 1”(土地)和“ 0”(水),计算岛屿的数量。一个岛屿被水包围,是通过水平或垂直连接相邻的陆地而形成的。您可以假定网格的所有四个边缘都被水包围。
Example :
Input:
11110
11010
11000
00000
Output: 1
class Solution {
int m, n;
boolean visited[][];
int[][] move;
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) return 0;
m = grid.length;
n = grid[0].length;
visited = new boolean[m][n];
move = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (!visited[i][j] && grid[i][j] =='1'){
fill(grid, i, j);
count++;
}
}
}
return count;
}
private void fill(char[][] grid, int x, int y) {
visited[x][y] = true;
for (int i = 0; i < 4; i++) {
int newX = x + move[i][0];
int newY = y + move[i][1];
if (isArea(newX, newY) && !visited[newX][newY] && grid[newX][newY] == '1') {
fill(grid, newX, newY);
}
}
}
private boolean isArea(int x, int y) {
return x >= 0 && x < m && y >= 0 && y < n;
}
}
92 Happy Number
编写算法以确定数字是否为“ happy”。一个快乐的数字是由以下过程定义的数字:以任何正整数开头,用该数字的平方和代替该数字,然后重复该过程,直到该数字等于1(它将停留在该数字处),否则它将循环在不包含1的循环中无休止地循环。以1结尾的那些数字是快乐数字。
Example:
Input: 19
Output: true
Explanation:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
class Solution {
public boolean isHappy(int n) {
String num = n + "";
int sum = 0;
HashSet<Integer> set = new HashSet<Integer>();
for (int i = 0; i < num.length(); i++) {
sum += (num.charAt(i) - '0') * (num.charAt(i) - '0');
if (i + 1 == num.length() && sum == 1) {
return true;
}
if (i + 1 == num.length() && sum != 1) {
if (!set.add(sum))
return false;
i = -1;
num = sum + "";
sum = 0;
}
}
return false;
}
}
93 Count Primes
找到n以内的所有素数
class Solution {
// 找到n以内的所有素数个数
public int countPrimes(int n) {
//默认值是false,如果是不是素数我们标为true
//当然你也可以使用 Arrays.fill(f, true); 默认全设为true,如果不是素数我们设为false
boolean s[] = new boolean[n];
//如果n小于3的话就没有 因为找到n以内 所以2以内是没有的
if (n < 3) return 0;
//c 可以理解为最多的素数个数
//以为我们知道所有的偶数都不是素数,所有我们可以剔除一半
//但是你可能会有疑问 2 不是偶数吗 --> 这里 2 和 1 相抵消
//比如 5 以内的话 5 / 2 = 2 素数就为 2 和 3
//首先我们假设 小于 c 的奇数全是素数
int c = n / 2;
// 之后我们只要剔除 在这个奇数范围内 不是素数的数就可以了
// 因为我们已经把偶数去掉了,所以只要剔除奇数的奇数倍就可以了
for (int i = 3; i * i < n; i += 2) {
//说明 i 是不是素数,而且已经是剔除过的
if (s[i])
continue;
//这里是计算c 中剔除完不是素数的奇数个数 下面解释各个值的含义
//我们要剔除的是 i 的 奇数倍
//为什么是 i * i开始呢 我们打个比方,假设我们此时i = 5
//那么我们开始剔除 j = 1 时就是本身,此时要么已经被剔除,要么就是素数,所以 1 不考虑
//当 j = 2 || j = 4时,乘积为偶数所以也不在我们考虑范围内
//当 j = 3时,我们考虑 3 * 5 但是这种情况已经是当 i = 3的时候被考虑进去了所以我们只要考虑之后的就可以了
//那么为什么 j = j + i * 2呢
//根据上面所说 我们从3开始考虑 3 * 3,3 * 5,3 * 7....只要 j < n 我们就剔除
//带入i : i * i, i * ( i + 2 ) , i * ( i + 4 )....
for (int j = i * i; j < n; j += i * 2) {
//只要找到c个奇数中的合数,c就减1,把 j标记为非素数
if (!s[j]) {
s[j] = true;
c--;
}
}
}
return c;
}
}
94 Reverse Linked List
反转链表
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null)return null;
ListNode pre = null;
ListNode node = head;
while(node != null) {
ListNode next = node.next;
node.next = pre;
pre = node;
node = next;
}
return pre;
}
}
95 Course Schedule(图)
您必须参加总共numCourses课程,从0到numCourses-1标记。某些课程可能有先决条件,例如,要学习课程0,您必须首先学习课程1,该课程以一对表示:[0,1]给定课程总数和先决条件对列表,您是否可以完成所有课程?
Example 1:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
Example 2:
Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0, and to take course 0 you should
also have finished course 1. So it is impossible.
96 Implement Trie (Prefix Tree)
实现一个单词查找树与插入、搜索和startsWith
class Trie {
TrieNode root;
/**
* Initialize your data structure here.
*/
public Trie() {
root = new TrieNode();
}
/**
* Inserts a word into the trie.
*/
public void insert(String word) {
TrieNode p = root;
for (char c : word.toCharArray()) {
if (p.kids[c - 'a'] == null) {
p.kids[c - 'a'] = new TrieNode();
}
p = p.kids[c - 'a'];
}
p.isEnd = true;
}
/**
* Returns if the word is in the trie.
*/
public boolean search(String word) {
TrieNode p = root;
for (char c : word.toCharArray()) {
if (p.kids[c - 'a'] == null) {
return false;
}
p = p.kids[c - 'a'];
}
return p.isEnd;
}
/**
* Returns if there is any word in the trie that starts with the given prefix.
*/
public boolean startsWith(String prefix) {
TrieNode p = root;
for (char c : prefix.toCharArray()) {
if (p.kids[c - 'a'] == null) {
return false;
}
p = p.kids[c - 'a'];
}
return true;
}
}
class TrieNode {
TrieNode[] kids;
boolean isEnd;
public TrieNode() {
kids = new TrieNode[26];
isEnd = false;
}
}
97 Word Search II
给定2D木板和词典中的单词列表,请在木板中查找所有单词。每个单词必须由顺序相邻的单元格的字母构成,其中“相邻”单元格是水平或垂直相邻的单元格。同一字母单元在一个单词中最多只能使用一次。
Example:
Input:
board = [
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
words = ["oath","pea","eat","rain"]
Output: ["eat","oath"]
class Solution {
public List<String> findWords(char[][] board, String[] words) {
List<String> res = new ArrayList<>();
TrieNode root = buildTrie(words);
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
dfs(board, i, j, root, res);
}
}
return res;
}
private void dfs(char[][] board, int i, int j, TrieNode root, List<String> res) {
char ch = board[i][j];
if (ch == '#' || root.next[ch - 'a'] == null) return;
if (root.next[ch - 'a'].word != null) {
res.add(root.next[ch - 'a'].word);
root.next[ch - 'a'].word = null;
}
root = root.next[ch - 'a'];
board[i][j] = '#';
if (i > 0) dfs(board, i - 1, j, root, res);
if (j > 0) dfs(board, i, j - 1, root, res);
if (i < board.length - 1) dfs(board, i + 1, j, root, res);
if (j < board[0].length - 1) dfs(board, i, j + 1, root, res);
board[i][j] = ch;
}
class TrieNode {
String word;
TrieNode[] next = new TrieNode[26];
}
private TrieNode buildTrie(String[] words) {
TrieNode root = new TrieNode();
for (String w : words) {
TrieNode p = root;
for (char ch : w.toCharArray()) {
if (p.next[ch - 'a'] == null) {
p.next[ch - 'a'] = new TrieNode();
}
p = p.next[ch - 'a'];
}
p.word = w;
}
return root;
}
}
98 Maximum Subarray
class Solution {
public int maxSubArray(int[] nums) {
int max = nums[0];
int res = nums[0];
for(int i = 1; i < nums.length; i ++){
max = Math.max(nums[i] , max + nums[i]);
res = Math.max(res , max);
}
return res;
}
}
99 Kth Largest Element in an Array
找到一个无序数组中的最大k元素。返回坐标。
Kth Largest Element in an Array
public class Solution {
public int findKthLargest(int[] arr, int k) {
if (arr == null || arr.length == 0)
return 0;
int n = arr.length;
int start = 0;
int end = n - 1;
int index = partition(arr, start, end);
while (index != k - 1) {
if (index > k - 1) {
end = index - 1;
} else {
start = index + 1;
}
index = partition(arr, start, end);
}
return arr[index];
}
private int partition(int[] arr, int l, int r) {
int tmp = arr[l];
while (l < r) {
while (l < r && arr[r] <= tmp) r--;
arr[l] = arr[r];
while (l < r && arr[l] >= tmp) l++;
arr[r] = arr[l];
}
arr[l] = tmp;
return l;
}
}
100 Contains Duplicate
给定一个整数数组,查找该数组是否包含任何重复项。
如果任何值在数组中至少出现两次,则函数应返回true;如果每个元素都不同,则函数应返回false。
class Solution
{
public boolean containsDuplicate(int[] nums)
{
HashSet<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++)
if (!set.add(nums[i]))
return true;
return false;
}
}