private static int trap(int[] height) {
if (height == null || height.length <= 1)
return 0;
//找到最高点
int maxH = height[0];
int maxIndex = 0;
for (int i=1; i<height.length; i++) {
if (height[i] >= maxH) {
maxH = height[i];
maxIndex = i;
}
}
//从左边开始遍历
int max = 0;
int h = height[0];
for (int i=1; i<maxIndex; i++) {
if (height[i] < h) {
max += h - height[i];
} else {
h = height[i];
}
}
h = height[height.length-1];
for (int i=height.length-1; i>maxIndex; i--) {
if (height[i] < h) {
max += h - height[i];
} else {
h = height[i];
}
}
return max;
}
public static int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0)
return 0;
int maxArea = Integer.MIN_VALUE;
for (int i=0; i<heights.length; i++) {
int h = heights[i];
int w = 1;
int j=i+1;
while (j < heights.length && heights[j] >= h) {
w++;
j++;
}
j=i-1;
while (j >= 0 && heights[j] >= h) {
w++;
j--;
}
maxArea = Math.max(maxArea, w*h);
}
return maxArea;
}
leetcode原题讲解
public class Solution94 {
//递归
List<Integer> res = new ArrayList<>();
private List<Integer> inorderTraversal(TreeNode root) {
if (root == null)
return res;
if (root.left != null)
inorderTraversal(root.left);
res.add(root.val);
if (root.right != null)
inorderTraversal(root.right);
return res;
}
//用栈
private List<Integer> inorderTraversal2(TreeNode root){
List<Integer> list = new ArrayList<>();
if (root == null)
return null;
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()) {
if (root != null) {
stack.push(root);
root = root.left;
} else {
root = stack.pop();
list.add(root.val);
root = root.right;
}
}
return list;
}
public class Solution144 {
//递归
List<Integer> res = new ArrayList<>();
private List<Integer> preorderTraversal(TreeNode root) {
if (root == null)
return res;
res.add(root.val);
if (root.left != null)
preorderTraversal(root.left);
if (root.right != null)
preorderTraversal(root.right);
return res;
}
}
//非递归
private static List<Integer> preorderTraversal2(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root == null)
return list;
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()) {
if (root != null) {
list.add(root.val);
stack.push(root);
root = root.left;
} else {
root = stack.pop();
root = root.right;
}
}
return list;
}
List<Integer> res = new ArrayList<>();
private List<Integer> postorderTraversal(TreeNode root) {
if (root == null)
return res;
if (root.left != null)
postorderTraversal(root.left);
if (root.right != null)
postorderTraversal(root.right);
res.add(root.val);
return res;
}
private static List<Integer> postorderTraversal2(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root == null)
return list;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = null;
TreeNode lastVisit = null;
stack.push(root);
while (!stack.isEmpty()) {
cur = stack.peek();
//如果cur没有孩子,或者孩子都访问过了,则访问并出栈
if ((cur.left == null && cur.right == null)||((lastVisit != null && lastVisit == cur.right)||
(lastVisit != null && lastVisit == cur.left))) {
list.add(cur.val);
lastVisit = cur;
stack.pop();
} else {
if (cur.right != null)
stack.push(cur.right);
if (cur.left != null)
stack.push(cur.left);
}
}
return list;
}
public class Solution103 {
//二叉树的锯齿遍历
private static 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.push(root);
while (!stack1.isEmpty() || !stack2.isEmpty()) {
List<Integer> list = new ArrayList<>();
if (!stack1.isEmpty()) {
while (!stack1.isEmpty()) {
root = stack1.pop();
list.add(root.val);
if (root.left != null)
stack2.push(root.left);
if (root.right != null)
stack2.push(root.right);
}
res.add(list);
} else {
while (!stack2.isEmpty()) {
root = stack2.pop();
list.add(root.val);
if (root.right != null)
stack1.push(root.right);
if (root.left != null)
stack1.push(root.left);
}
res.add(list);
}
}
return res;
}
}
class BSTIterator2 {
Stack<TreeNode> stack = new Stack<>();
public BSTIterator2(TreeNode root) {
if (root == null)
return;
stack.push(root);
while (root.left != null){
stack.push(root.left);
root = root.left;
}
}
/** @return the next smallest number */
public int next() {
TreeNode node = stack.pop();
if (node.right != null) {
stack.push(node.right);
TreeNode tmp = node.right;
while (tmp.left != null) {
stack.push(tmp.left);
tmp = tmp.left;
}
}
return node.val;
}
/** @return whether we have a next smallest number */
public boolean hasNext() {
return !stack.isEmpty();
}
}
public class Solution215 {
//数组中第k大的元素
private static int findKthLargest(int[] nums, int k) {
if (nums==null || nums.length == 0 || k> nums.length)
return 0;
//这是一个小顶堆
PriorityQueue<Integer> pq = new PriorityQueue<>((n1, n2)->n1-n2);
for (int i=0; i<nums.length; i++) {
pq.add(nums[i]);
if (pq.size() > k)
pq.poll();
}
return pq.poll();
}
}
public class Solution239 {
/**
* 滑动窗口的最大值
* */
//暴力法的时间复杂度为O(nk)
//堆的时间复杂度是O(nlog2k)
private static int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length < k)
return null;
if (nums.length == 0)
return new int[0];
int[] res = new int[nums.length-k+1];
int index = 0;
//建大顶堆
PriorityQueue<Integer> heap = new PriorityQueue<>((n1, n2)->n2-n1);
for (int i=0; i<nums.length; i++) {
heap.add(nums[i]);
if (heap.size() > k) {
heap.remove(nums[i-k]);
}
if (i >= k-1) {
res[index++] = heap.peek();
}
}
return res;
}
}
public class Solution113 {
private static List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
if (root == null)
return res;
tmp.add(root.val);
pathSumUtil(root, sum-root.val, res, tmp);
return res;
}
private static void pathSumUtil(TreeNode root, int sum,
List<List<Integer>> res, List<Integer> tmp) {
if (root.left == null && root.right == null && 0==sum) {
//这里为什么这么写?因为地址,后面就改地址了
res.add(new ArrayList<>(tmp));
return;
}
if (root.left != null) {
tmp.add(root.left.val);
pathSumUtil(root.left, sum-root.left.val, res, tmp);
tmp.remove(tmp.size()-1);
}
if (root.right != null) {
tmp.add(root.right.val);
pathSumUtil(root.right, sum-root.right.val, res, tmp);
tmp.remove(tmp.size()-1);
}
}
}
本题学习怎么二维数组排序。
public class Solution56 {
//合并区间
private static int[][] merge(int[][] intervals) {
List<int[]> res = new ArrayList<>();
//多维矩阵排序
if (intervals == null || intervals.length <= 0)
return res.toArray(new int[0][]);
// Arrays.sort(intervals, (a, b) -> a[0] - b[0]);// a[0] - b[0]大于0就交换顺序
// 根据二维数组第一个数字大小按每一行整体排序
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0]-o2[0];
}
});
int i=0;
while (i < intervals.length) {
int left = intervals[i][0];
int right = intervals[i][1];
// i不能到最后一行,所以要小于(数组的长度 - 1)
// 判断所在行的right和下一行的left大小,对right重新进行赋最大值,之后再不断进行while循环判断
while (i < intervals.length - 1 && right >= intervals[i + 1][0]) {
i++;
right = Math.max(right, intervals[i][1]);
}
res.add(new int[] { left, right });
i++;
}
return res.toArray(new int[0][]);
}
}
这里学习自定义比较器
public class Solution179 {
private static class LargestNumberComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
String s1 = o1+o2;
String s2 = o2+o1;
return s2.compareTo(s1);
}
}
//最大数,按首位较大排序
private static String largestNumber(int[] nums) {
String[] numsStr = new String[nums.length];
for (int i=0; i<nums.length; i++) {
numsStr[i] = String.valueOf(nums[i]);
}
Arrays.sort(numsStr, new LargestNumberComparator());
if ("0".equals(numsStr[0]))
return "0";
String res = "";
for (int i=0; i<numsStr.length; i++)
res += numsStr[i];
return res;
}
}
class Solution {
public void flatten(TreeNode root) {
while (root != null) {
//左子树为空,直接考虑右子树
if (root.left == null) {
root = root.right;
} else {
//找到左子树最右边的节点
TreeNode pre = root.left;
while (pre.right != null)
pre = pre.right;
//将原来的右子树接到左子树的最右边节点
pre.right = root.right;
//将左子树插到右子树的地方
root.right = root.left;
root.left = null;
//考虑下一个节点
root = root.right;
}
}
}
}
阿里面试问到了这道题,但是我没有这个思路,跪了。
class Foo {
public Semaphore sema_first_two = new Semaphore(0);
public Semaphore sema_two_second = new Semaphore(0);
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
// printFirst.run() outputs "first". Do not change or remove this line.
printFirst.run();
sema_first_two.release();
}
public void second(Runnable printSecond) throws InterruptedException {
// printSecond.run() outputs "second". Do not change or remove this line.
sema_first_two.acquire();
printSecond.run();
sema_two_second.release();
}
public void third(Runnable printThird) throws InterruptedException {
sema_two_second.acquire();
// printThird.run() outputs "third". Do not change or remove this line.
printThird.run();
}
}
其实是中序遍历之间的和
public class Solution938 {
/**
* 中序遍历之间的节点的和
* */
private static int rangeSumBST(TreeNode root, int L, int R) {
if (root == null)
return 0;
if (root.val <= R && root.val >= L) {
return root.val + rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R);
} else if (root.val < L) {
return rangeSumBST(root.right, L, R);
} else {
return rangeSumBST(root.left, L, R);
}
}
}
class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length <= 0)
return -1;
int l = 0, h = nums.length-1;
int mid;
while (l <= h) {
mid = (l + h)/2;
if (nums[mid] == target)
return mid;
if (nums[mid] < nums[h]) { //说明mid右边单调递增
if (target <= nums[h] && target >= nums[mid]) {
l = mid+1;
} else {
h = mid-1;
}
} else { //说明mid左边单调递增
if (target < nums[mid] && target >= nums[l]) {
h = mid-1;
} else {
l = mid+1;
}
}
}
return -1;
}
}
这题的问题在于每次总是搞不清楚坐标的变换,非常不熟练,因此记录。
//顺线变换坐标
public class Solution {
private static void rotate(int[][] matrix) {
for (int i=0; i<matrix.length/2; i++) {
for (int j=i; j<matrix[0].length-i-1; j++) {
int tmp = matrix[i][j];
matrix[i][j] = matrix[matrix.length-1-j][i];
matrix[matrix.length-1-j][i] = matrix[matrix.length-1-i][matrix.length-1-j];
matrix[matrix.length-1-i][matrix.length-1-j] = matrix[j][matrix.length-1-i];
matrix[j][matrix.length-1-i] = tmp;
}
}
}
}
实际也是一道动态规划题。
状态转移方程:第i天的最大收益=max(第i-1天的最大收益,第i天的股价-前i-1天的最小股价)
代码:
private static int maxProfit(int[] prices){
if (prices == null || prices.length <= 1)
return 0;
int maxProfit=0;
int min = prices[0];
for (int i=1; i<prices.length; i++) {
maxProfit = Math.max(maxProfit, prices[i]-min);
if (prices[i] < min) {
min = prices[i];
}
}
return maxProfit;
}
二分法也可以做:
规律:
代码:
private static int findPeakElement2(int[] nums) {
if (nums == null || nums.length <= 1)
return 0;
int low = 0, high = nums.length-1;
int mid;
while (low <= high) {
mid = (low + high) >> 1;
if ((mid == 0 && nums[mid] > nums[mid+1])
||(mid==nums.length-1 && nums[mid] > nums[mid-1])
||(nums[mid] > nums[mid+1] && nums[mid] > nums[mid-1])) {
return mid;
} else if (nums[mid] > nums[mid+1]) {
high = mid-1;
} else {
low = mid+1;
}
}
return -1;
}
这题是easy题,但是没有想到最佳做法,因此记录下来:
class Solution {
public int majorityElement(int[] nums) {
int ret = nums[0];
int count = 1;
for(int num : nums) {
if(num != ret) {
count--;
if(count == 0) {
count = 1;
ret = num;
}
}
else
count++;
}
return ret;
}
}
public class Solution142 {
private static ListNode getIntersect(ListNode head){
if (head == null || head.next == null) {
return null;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow)
return fast;
}
return null;
}
/**
* 环形链表
* */
private static ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
ListNode fast = getIntersect(head);
if (fast == null) {
System.out.println("no cycle");
return null;
}
ListNode ptr1 = head;
ListNode ptr2 = fast;
int index = 0;
while (ptr1 != ptr2) {
ptr1 = ptr1.next;
ptr2 = ptr2.next;
index++;
}
return ptr1;
}
}