这里写目录标题
- 冒泡
- 选择排序
- 插入排序
- 希尔
- 归并排序
- 快速排序
- 堆排序
- 25. K 个一组翻转链表 9
- 3. 无重复字符的最长子串 8
- 102. 二叉树的层序遍历 6
- 124. 二叉树中的最大路径和 6
- 206. 反转链表 6
- 15. 三数之和 6
- 146. LRU缓存机制 6
- 215. 数组中的第K个最大元素 5
- 2. 两数相加 5
- 141. 环形链表 5
- 234. 回文链表 5
- 155. 最小栈 4
- 105. 从前序与中序遍历序列构造二叉树 4
- 33. 搜索旋转排序数组 4
- 160. 相交链表 4
- 128. 最长连续序列 4
- 103. 二叉树的锯齿形层次遍历 4
- 113. 路径总和 II 4
- 121.买卖股票 3
- 108. 将有序数组转换为二叉搜索树 3
- 88. 合并两个有序数组 3
- 162. 寻找峰值 3
- 56. 合并区间 3
- 110. 平衡二叉树 3
- 236. 二叉树的最近公共祖先 3
- 322. 零钱兑换 3
- 101. 对称二叉树 3
- 20. 有效的括号 3
- 143. 重排链表 3
- 54. 螺旋矩阵 2
- 221. 最大正方形 2
- 23. 合并K个排序链表 2
- 83. 删除排序链表中的重复元素 2
- 70. 爬楼梯 2
- 剑指 Offer 61. 扑克牌中的顺子 2
- 32. 最长有效括号 2
- 剑指 Offer 42. 连续子数组的最大和 2
- 415. 字符串相加 2
- 41. 缺失的第一个正数 2
- 704. 二分查找 2
- 958. 二叉树的完全性检验 2
- 后端 69. x 的平方根 2
- 114. 二叉树展开为链表 2
https://www.cnblogs.com/guoyaohua/p/8600214.html
这里写目录标题
- 冒泡
- 选择排序
- 插入排序
- 希尔
- 归并排序
- 快速排序
- 堆排序
- 25. K 个一组翻转链表 9
- 3. 无重复字符的最长子串 8
- 102. 二叉树的层序遍历 6
- 124. 二叉树中的最大路径和 6
- 206. 反转链表 6
- 15. 三数之和 6
- 146. LRU缓存机制 6
- 215. 数组中的第K个最大元素 5
- 2. 两数相加 5
- 141. 环形链表 5
- 234. 回文链表 5
- 155. 最小栈 4
- 105. 从前序与中序遍历序列构造二叉树 4
- 33. 搜索旋转排序数组 4
- 160. 相交链表 4
- 128. 最长连续序列 4
- 103. 二叉树的锯齿形层次遍历 4
- 113. 路径总和 II 4
- 121.买卖股票 3
- 108. 将有序数组转换为二叉搜索树 3
- 88. 合并两个有序数组 3
- 162. 寻找峰值 3
- 56. 合并区间 3
- 110. 平衡二叉树 3
- 236. 二叉树的最近公共祖先 3
- 322. 零钱兑换 3
- 101. 对称二叉树 3
- 20. 有效的括号 3
- 143. 重排链表 3
- 54. 螺旋矩阵 2
- 221. 最大正方形 2
- 23. 合并K个排序链表 2
- 83. 删除排序链表中的重复元素 2
- 70. 爬楼梯 2
- 剑指 Offer 61. 扑克牌中的顺子 2
- 32. 最长有效括号 2
- 剑指 Offer 42. 连续子数组的最大和 2
- 415. 字符串相加 2
- 41. 缺失的第一个正数 2
- 704. 二分查找 2
- 958. 二叉树的完全性检验 2
- 后端 69. x 的平方根 2
- 114. 二叉树展开为链表 2
冒泡
/**
* 冒泡排序
*
* @param array
* @return
*/
public static int[] bubbleSort(int[] array) {
if (array.length == 0)
return array;
for (int i = 0; i < array.length; i++)
for (int j = 0; j < array.length - 1 - i; j++)
if (array[j + 1] < array[j]) {
int temp = array[j + 1];
array[j + 1] = array[j];
array[j] = temp;
}
return array;
}
选择排序
/**
* 选择排序
* @param array
* @return
*/
public static int[] selectionSort(int[] array) {
if (array.length == 0)
return array;
for (int i = 0; i < array.length; i++) {
int minIndex = i;
for (int j = i; j < array.length; j++) {
if (array[j] < array[minIndex]) //找到最小的数
minIndex = j; //将最小数的索引保存
}
int temp = array[minIndex];
array[minIndex] = array[i];
array[i] = temp;
}
return array;
}
插入排序
/**
* 插入排序
* @param array
* @return
*/
public static int[] insertionSort(int[] array) {
if (array.length == 0)
return array;
int current;
for (int i = 0; i < array.length - 1; i++) {
current = array[i + 1];
int preIndex = i;
while (preIndex >= 0 && current < array[preIndex]) {
array[preIndex + 1] = array[preIndex];
preIndex--;
}
array[preIndex + 1] = current;
}
return array;
}
希尔
/**
* 希尔排序
*
* @param array
* @return
*/
public static int[] ShellSort(int[] array) {
int len = array.length;
int temp, gap = len / 2;
while (gap > 0) {
for (int i = gap; i < len; i++) {
temp = array[i];
int preIndex = i - gap;
while (preIndex >= 0 && array[preIndex] > temp) {
array[preIndex + gap] = array[preIndex];
preIndex -= gap;
}
array[preIndex + gap] = temp;
}
gap /= 2;
}
return array;
}
归并排序
/**
* 归并排序
*
* @param array
* @return
*/
public static int[] MergeSort(int[] array) {
if (array.length < 2) return array;
int mid = array.length / 2;
int[] left = Arrays.copyOfRange(array, 0, mid);
int[] right = Arrays.copyOfRange(array, mid, array.length);
return merge(MergeSort(left), MergeSort(right));
}
/**
* 归并排序——将两段排序好的数组结合成一个排序数组
*
* @param left
* @param right
* @return
*/
public static int[] merge(int[] left, int[] right) {
int[] result = new int[left.length + right.length];
for (int index = 0, i = 0, j = 0; index < result.length; index++) {
if (i >= left.length)
result[index] = right[j++];
else if (j >= right.length)
result[index] = left[i++];
else if (left[i] > right[j])
result[index] = right[j++];
else
result[index] = left[i++];
}
return result;
}
快速排序
import java.util.Random;
public class Solution {
// 快速排序 1:基本快速排序
/**
* 列表大小等于或小于该大小,将优先于 quickSort 使用插入排序
*/
private static final int INSERTION_SORT_THRESHOLD = 7;
private static final Random RANDOM = new Random();
public int[] sortArray(int[] nums) {
int len = nums.length;
quickSort(nums, 0, len - 1);
return nums;
}
private void quickSort(int[] nums, int left, int right) {
// 小区间使用插入排序
if (right - left <= INSERTION_SORT_THRESHOLD) {
insertionSort(nums, left, right);
return;
}
//细节
int pIndex = partition(nums, left, right);
quickSort(nums, left, pIndex - 1);
quickSort(nums, pIndex + 1, right);
}
/**
* 对数组 nums 的子区间 [left, right] 使用插入排序
*
* @param nums 给定数组
* @param left 左边界,能取到
* @param right 右边界,能取到
*/
private void insertionSort(int[] nums, int left, int right) {
for (int i = left + 1; i <= right; i++) {
int temp = nums[i];
int j = i;
while (j > left && nums[j - 1] > temp) {
nums[j] = nums[j - 1];
j--;
}
nums[j] = temp;
}
}
private int partition(int[] nums, int left, int right) {
int randomIndex = RANDOM.nextInt(right - left + 1) + left;
swap(nums, left, randomIndex);
// 基准值
int pivot = nums[left];
int lt = left;
// 循环不变量:
// all in [left + 1, lt] < pivot
// all in [lt + 1, i) >= pivot
for (int i = left + 1; i <= right; i++) {
if (nums[i] < pivot) {
lt++;
swap(nums, i, lt);
}
}
swap(nums, left, lt);
return lt;
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}
堆排序
public class Solution {
public int[] sortArray(int[] nums) {
int len = nums.length;
// 将数组整理成堆
heapify(nums);
// 循环不变量:区间 [0, i] 堆有序
for (int i = len - 1; i >= 1; ) {
// 把堆顶元素(当前最大)交换到数组末尾
swap(nums, 0, i);
// 逐步减少堆有序的部分
i--;
// 下标 0 位置下沉操作,使得区间 [0, i] 堆有序
siftDown(nums, 0, i);
}
return nums;
}
/**
* 将数组整理成堆(堆有序)
*
* @param nums
*/
private void heapify(int[] nums) {
int len = nums.length;
// 只需要从 i = (len - 1) / 2 这个位置开始逐层下移
for (int i = (len - 1) / 2; i >= 0; i--) {
siftDown(nums, i, len - 1);
}
}
/**
* @param nums
* @param k 当前下沉元素的下标
* @param end [0, end] 是 nums 的有效部分
*/
private void siftDown(int[] nums, int k, int end) {
while (2 * k + 1 <= end) {
int j = 2 * k + 1;
if (j + 1 <= end && nums[j + 1] > nums[j]) {
j++;
}
if (nums[j] > nums[k]) {
swap(nums, j, k);
} else {
break;
}
k = j;
}
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}
写了好多忘了保存又打开了新的一个,之前写的都没了
25. K 个一组翻转链表 9
使用递归太巧妙了,这是我做过的用递归最好用的题之一,迭代的细节很多,用递归生生做成了一道简单题。
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if(head==null) return null;
ListNode cur = head;
int i = k;
// 先遍历找到下一段的开头
while(i>0&&cur!=null){
cur = cur.next;
i--;
}
// 如果没有到k个,那么原顺序返回
if(i>0) return head;
// 关键在于这个位置,返回值拼接到当前段翻转后的尾结点即可
// 而尾结点就是原链表在当前段的头
ListNode pre = reverseKGroup(cur,k);
i = k;
while(i>0){
ListNode temp = head.next;
head.next = pre;
pre = head;
head = temp;
i--;
}
return pre;
}
}
3. 无重复字符的最长子串 8
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();
int[] dic = new int[128];
Arrays.fill(dic, -1);
int cur = 0;
int max = 0;
for (int i = 0; i < len; i++) {
int thisC = i - dic[s.charAt(i)];
// thisC是当前字符自从上次出现后的最大长度
if(thisC > cur){
cur++;
}else{
cur = thisC;
}
max = Math.max(max, cur);
dic[s.charAt(i)] = i;
}
return max;
}
}
102. 二叉树的层序遍历 6
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Deque<TreeNode> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()){
int size = q.size();
List<Integer> t = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode cur = q.poll();
if(cur != null){
t.add(cur.val);
q.add(cur.left);
q.add(cur.right);
}
}
if(t.size() > 0) res.add(t);
}
return res;
}
}
124. 二叉树中的最大路径和 6
class Solution {
private int res = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
helper(root);
return res;
}
// 返回的是以root的值为头节点的最大的路径
private int helper(TreeNode root){
if(root==null) return 0;
int le = Math.max(0, helper(root.left));
int ri = Math.max(0, helper(root.right));
res = Math.max(res, le + ri + root.val);
return root.val + Math.max(le, ri);
}
}
206. 反转链表 6
class Solution {
public ListNode reverseList(ListNode head) {
//迭代
ListNode pre = null;
while (head != null){
ListNode temp = head.next;
head.next = pre;
pre = head;
head = temp;
}
return pre;
}
}
15. 三数之和 6
动态双指针,注意双指针是哪俩。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int k = 0; k < nums.length-2; k++){
if(nums[k]>0) break;
if(k>0 && nums[k]==nums[k-1]) continue;
int i = k + 1, j = nums.length-1;
while(i < j){
int sum = nums[i]+nums[j]+nums[k];
if(sum<0){
while(i<j && nums[i] == nums[++i]){
}
}else if(sum>0){
while(i<j && nums[j] == nums[--j]){
}
}else{
res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
while(i<j && nums[i] == nums[++i]){
}
while(i<j && nums[j] == nums[--j]){
}
}
}
}
return res;
}
}
146. LRU缓存机制 6
- map和双向链表来保存
- 对外暴露get和put的方法,参数是int和<int,int>调用add和remove的参数是Node
- get的逻辑:
- map中是否有node
- 有的话得到node
- 在链表中移除node
- 在链表末尾增加node
- 返回node的值
- put的逻辑
- 先看原map中有没有这个值,有的话移除
- 看下map的大小是否超出容量,超的话将head移除
class LRUCache {
Node head = new Node(0, 0), tail = new Node(0, 0);
Map<Integer, Node> map = new HashMap<>();
int max_len;
public LRUCache(int capacity) {
max_len = capacity;
// 建立双链表
head.next = tail;
tail.prev = head;
}
public int get(int key) {
if (map.containsKey(key)) {
Node node = map.get(key);
remove(node);
add(node);
return node.value;
} else
return -1;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
remove(map.get(key));
}
// 把表头位置节点删除(说明最近的数据值)
if (map.size() == max_len) {
remove(head.next);
}
add(new Node(key, value));
}
// 删除链表
private void remove(Node node) {
map.remove(node.key);
// 删除节点
node.prev.next = node.next;
node.next.prev = node.prev;
}
// 加在链表尾
private void add(Node node) {
map.put(node.key, node);
Node pre_tail = tail.prev;
node.next = tail;
tail.prev = node;
pre_tail.next = node;
node.prev = pre_tail;
}
// 创建双向链表
class Node {
Node prev, next;
int key, value;
Node(int _key, int _value) {
key = _key;
value = _value;
}
}
}
作者:powcai
链接:https://leetcode-cn.com/problems/lru-cache/solution/pythonde-ordereddict-huo-zhe-ha-xi-shuang-xiang-li/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
215. 数组中的第K个最大元素 5
使用优先队列。
public int findKthLargest(int[] nums, int k) {
final PriorityQueue<Integer> queue = new PriorityQueue<>();
for (int val : nums) {
queue.add(val);
if (queue.size() > k)
queue.poll();
}
return queue.peek();
}
快排思路
class Solution {
private static Random random = new Random(System.currentTimeMillis());
public int findKthLargest(int[] nums, int k) {
int index = nums.length - k;
int left = 0;
int right = nums.length - 1;
//因为一定有第K大的值所以使用死循环也可以
while (true){
int temp = partition(nums, left, right);
if(temp == index) {return nums[index];}
else if (temp < index){
left = index + 1;
}else{
right = index - 1;
}
}
}
//partition的作用,将所有小于第一个的元素放到第一个元素的左边并且返回第一个元素(没随机交换时)
private int partition(int[] nums, int start, int end) {
if (end > start) {
int randomIndex = start + 1 + random.nextInt(end - start);
swap(nums, start, randomIndex);
}
int piviot = nums[start];
int j = start;
for (int i = start + 1; i <= end; i++) {
//到底是小于等于还是小于?
if(nums[i] < piviot) {
j++;
swap(nums,i,j);
}
}
swap(nums,start,j);
return j;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
2. 两数相加 5
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int c = 0;
ListNode res = new ListNode(-1);
ListNode cur = res;
while(l1 != null && l2 != null){
int sum = l1.val + l2.val + c;
c = sum/10;
cur.next = new ListNode(sum%10);
l1 = l1.next;
l2 = l2.next;
cur = cur.next;
}
while(l1 != null){
int sum = l1.val + c;
c = sum/10;
cur.next = new ListNode(sum%10);
l1 = l1.next;
cur = cur.next;
}
while(l2 != null){
int sum = l2.val + c;
c = sum/10;
cur.next = new ListNode(sum%10);
l2 = l2.next;
cur = cur.next;
}
if(c > 0) cur.next = new ListNode(c);
return res.next;
}
}
141. 环形链表 5
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode f = head;
ListNode s = head;
while(f != null && f.next != null){
f = f.next.next;
s = s.next;
if(f == s){
return true;
}
}
return false;
}
}
234. 回文链表 5
双指针法。
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null)
return true;
ListNode fast = head;
ListNode slow = head;
ListNode pre = null;
ListNode temp = null;
while (fast != null && fast.next != null){
fast = fast.next.next;
temp = slow.next;
slow.next = pre;
pre = slow;
slow = temp;
}
//此时pre是翻转后的头节点,
//一下是节点个数为奇数的情况
if(fast != null){
slow = slow.next;
}
while(pre != null){
if(pre.val != slow.val){
return false;
}
pre = pre.next;
slow = slow.next;
}
return true;
}
}
155. 最小栈 4
- 使用两个栈
- 当push的时候,先判断当前值和辅助栈栈顶相比谁小,当前小泽直接压入,辅助栈顶小则再次压入辅助栈顶
import java.util.Stack;
public class MinStack {
// 数据栈
private Stack<Integer> data;
// 辅助栈
private Stack<Integer> helper;
/**
* initialize your data structure here.
*/
public MinStack() {
data = new Stack<>();
helper = new Stack<>();
}
// 思路 1:数据栈和辅助栈在任何时候都同步
public void push(int x) {
// 数据栈和辅助栈一定会增加元素
data.add(x);
if (helper.isEmpty() || helper.peek() >= x) {
helper.add(x);
} else {
helper.add(helper.peek());
}
}
public void pop() {
// 两个栈都得 pop
if (!data.isEmpty()) {
helper.pop();
data.pop();
}
}
public int top() {
if(!data.isEmpty()){
return data.peek();
}
throw new RuntimeException("栈中元素为空,此操作非法");
}
public int getMin() {
if(!helper.isEmpty()){
return helper.peek();
}
throw new RuntimeException("栈中元素为空,此操作非法");
}
}
105. 从前序与中序遍历序列构造二叉树 4
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTreeHelper(preorder, inorder, (long)Integer.MAX_VALUE + 1);
}
int pre = 0;
int in = 0;
private TreeNode buildTreeHelper(int[] preorder, int[] inorder, long stop) {
//到达末尾返回 null
if(pre == preorder.length){
return null;
}
//到达停止点返回 null
//当前停止点已经用了,in 后移
if (inorder[in] == stop) {
in++;
return null;
}
int root_val = preorder[pre++];
TreeNode root = new TreeNode(root_val);
//左子树的停止点是当前的根节点
root.left = buildTreeHelper(preorder, inorder, root_val);
//右子树的停止点是当前树的停止点
root.right = buildTreeHelper(preorder, inorder, stop);
return root;
}
作者:windliang
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--22/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关:
LeetCode889 根据前序和后序遍历构造二叉树
LeetCode105 从前序与中序遍历序列构造二叉树
LeetCode106 从中序与后序遍历序列构造二叉树
33. 搜索旋转排序数组 4
我喜欢的二分法模板:
- 边界左右闭
- 循环条件小于
- 返回有前判断
- 寻找左边界,mid中间偏左
- 寻找右边界,mid中间偏右
class Solution {
public int search(int[] nums, int target) {
if(nums.length == 0) return -1;
int left = 0;
int right = nums.length - 1;
int mid = left + (right-left)/2;
while(left < right){
if(nums[mid] == target){
return mid;
}
if(nums[left] <= nums[mid]){ //左边升序
if(target >= nums[left] && target <= nums[mid]){//在左边范围内
right = mid;
}else{//只能从右边找
left = mid+1;
}
}else{ //右边升序
if(target >= nums[mid] && target <= nums[right]){//在右边范围内
left = mid ;
}else{//只能从左边找
right = mid - 1;
}
}
mid = left + (right-left)/2;
}
if(nums[left] == target) return left;
return -1; //没找到
}
}
160. 相交链表 4
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode l1 = headA;
ListNode l2 = headB;
while(l1 != l2){
l1 = l1 == null ? headB : l1.next;
l2 = l2 == null ? headA : l2.next;
}
return l1;
}
}
128. 最长连续序列 4
经典做法:对于
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) set.add(num);
int res = 0;
for (int num : nums){
if(!set.contains(num - 1));
//如果包含的话,在num - 1时候就计算过了
int temp = 1;
while(set.contains(num + temp)){
temp++;
}
res = Math.max(res, temp);
}
return res;
}
}
103. 二叉树的锯齿形层次遍历 4
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
Deque<TreeNode> q = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root == null) return res;
q.add(root);
boolean isForward = true;
while(!q.isEmpty()){
int size = q.size();
Deque<Integer> temp = new LinkedList<>();
while(size-- > 0){
TreeNode top = q.poll();
if(isForward){
temp.add(top.val);
}
else{
temp.addFirst(top.val);
}
if(top.left != null){
q.add(top.left);
}
if (top.right != null){
q.add(top.right);
}
}
isForward = !isForward;
res.add(new ArrayList<>(temp));
}
return res;
}
}
113. 路径总和 II 4
- 树的dfs比较简单,因为不会出现重复访问的情况,不必维持记忆数组。
- 不要在空节点处添加路径,因为会添加两次
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> res = new ArrayList<>();
bfs(res,new ArrayList<Integer>(),root,sum);
return res;
}
private void bfs(List<List<Integer>> res, ArrayList<Integer> temp, TreeNode root, int sum) {
if(root == null) return;
if(root.left == null && root.right == null){
ArrayList<Integer> path = new ArrayList<>(temp);
path.add(root.val);
sum -= root.val;
if(sum == 0) res.add(path);
return;
}
temp.add(root.val);
bfs(res, temp, root.left, sum - root.val);
bfs(res, temp, root.right, sum - root.val);
temp.remove(temp.size() - 1);
}
}
121.买卖股票 3
- 只需要维护个左侧最小值即可,最小值的更新是和当前比一下。
- 维护历史最大收益,然后利用当前值与最小值试图更新最大收益
class Solution {
public int maxProfit(int[] prices) {
//一个指针记录大小,;另一个记录res
int pre = Integer.MAX_VALUE;
int res = 0;
for (int i = 0; i < prices.length; i++) {
pre = Math.min(pre, prices[i]);
res = Math.max(prices[i] - pre, res);
}
return res;
}
}
108. 将有序数组转换为二叉搜索树 3
return root的模板
BST的中序遍历是升序的,因此本题等同于根据中序遍历的序列恢复二叉搜索树。因此我们可以以升序序列中的任一个元素作为根节点,以该元素左边的升序序列构建左子树,以该元素右边的升序序列构建右子树,这样得到的树就是一棵二叉搜索树啦~
又因为本题要求高度平衡,因此我们需要选择升序序列的中间元素作为根节点奥作者:sweetiee
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/solution/jian-dan-di-gui-bi-xu-miao-dong-by-sweetiee/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return dfs(nums, 0, nums.length - 1);
}
private TreeNode dfs(int[] nums, int s, int e) {
if (s > e) return null;
int m = s + (e - s ) / 2;
TreeNode root = new TreeNode(nums[m]);
root.left = dfs(nums, s, m - 1);
root.right = dfs(nums, m + 1, e);
return root;
}
}
88. 合并两个有序数组 3
和链表思路一样
162. 寻找峰值 3
因为左右边界都是无穷小,所以可以用二分搜索的方法,向上爬坡即可
class Solution {
public int findPeakElement(int[] nums) {
//找峰值,使用二分查找中间值小于右侧值说明在上升
int i = 0;
int j = nums.length-1;
while(i < j){
int m = i + (j - i)/2;
if(nums[m] < nums[m+1]){
i = m + 1;
}else j = m;
}
return i;
}
}
56. 合并区间 3
- 要熟悉使用
return Arrays.copyOf(res, idx + 1);
!感觉就像使用list一样! - 记住else更新结束值要使用最大的,不要直接赋当前值
class Solution {
public int[][] merge(int[][] intervals) {
// 先按照区间起始位置排序
Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
// 遍历区间
int[][] res = new int[intervals.length][2];
int idx = -1;
for (int[] interval: intervals) {
// 如果结果数组是空的,或者当前区间的起始位置 > 结果数组中最后区间的终止位置,
// 则不合并,直接将当前区间加入结果数组。
if (idx == -1 || interval[0] > res[idx][1]) {
res[++idx] = interval;
} else {
// 反之将当前区间合并至结果数组的最后区间
res[idx][1] = Math.max(res[idx][1], interval[1]);
}
}
return Arrays.copyOf(res, idx + 1);
}
}
作者:sweetiee
链接:https://leetcode-cn.com/problems/merge-intervals/solution/chi-jing-ran-yi-yan-miao-dong-by-sweetiee/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
110. 平衡二叉树 3
探究整棵树的是否满足性质,常用这种方法
- 对于左右子树直接递归调用
- 对本节点进行判断(判断方法还可能是递归)
class Solution {
public boolean isBalanced(TreeNode root) {
if(root == null) return true;
return (Math.abs(height(root.left) - height(root.right)) <= 1) && isBalanced(root.left) && isBalanced(root.right);
}
private int height(TreeNode root) {
if(root == null) return 0;
return Math.max(height(root.right), height(root.left)) + 1;
}
}
236. 二叉树的最近公共祖先 3
一般题目中,递归函数结果是符合函数要求的结果,只不过问题规模缩小了。而本题目中,当lowestCommonAncestor
的第一个参数
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root==q) return root;
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left == null && right==null){
return null;
}
if(left==null) return right; //说明下一级递归中的root不是null;
if(right==null) return left;
return root;
}
}
322. 零钱兑换 3
背包
class Solution {
public int coinChange(int[] coins, int amount) {
//01背包
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 0; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if(i >= coins[j]){
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] == amount + 1 ? -1 :dp[amount];
}
}
101. 对称二叉树 3
class Solution {
public boolean isSymmetric(TreeNode root) {
return dfs(root,root);
}
private boolean dfs(TreeNode le, TreeNode ri) {
if(le == null && ri == null) return true;
if(le == null || ri == null) return false;
return le.val == ri.val && isSymmetric(le) && isSymmetric(ri);
}
}
20. 有效的括号 3
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
for(int i = 0; i < s.length(); i++){
char c = s.charAt(i);
if(c=='(' || c=='[' || c=='{')
stack.push(c);
else{
if(stack.isEmpty()){
return false;
}
char old = stack.pop();
if(old=='(' && c == ')' || old=='['&& c == ']' || old=='{'&& c == '}'){
continue;
}
return false;
}
}
return stack.isEmpty();
}
}
143. 重排链表 3
1.将链表分成两部分,后部分翻转,每部分都尾置0防止纠缠
2.奇数个节点是,前一段比后一段多一个
class Solution {
public void reorderList(ListNode head) {
if(head == null) return;
//找到中点
ListNode d = new ListNode(-1);
d.next = head;
ListNode res = d;
ListNode f = head;
ListNode s = head;
while(f.next != null && f.next.next != null){
f = f.next.next;
s = s.next;
}
ListNode tail1 = s;
s = s.next;
tail1.next = null;
ListNode pre = null;
// 翻转后面的
while(s != null){
ListNode t = s.next;
s.next = pre;
pre = s;
s = t;
}
while (head != null && pre != null){
d.next = head;
head = head.next;
d = d.next;
d.next = pre;
pre = pre.next;
d = d.next;
}
if(head != null){
d.next = head;
}
head = res.next;
}
}
54. 螺旋矩阵 2
这个算是比较清楚的,
当行或列是奇数时,后两个要判断是否重复
在这里插入代码片public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> list = new ArrayList<Integer>();
if(matrix == null || matrix.length == 0)
return list;
int m = matrix.length;
int n = matrix[0].length;
int i = 0;
//统计矩阵从外向内的层数,如果矩阵非空,那么它的层数至少为1层
int count = (Math.min(m, n)+1)/2;
//从外部向内部遍历,逐层打印数据
while(i < count) {
for (int j = i; j < n-i; j++) {
list.add(matrix[i][j]);
}
for (int j = i+1; j < m-i; j++) {
list.add(matrix[j][(n-1)-i]);
}
for (int j = (n-1)-(i+1); j >= i && (m-1-i != i); j--) {
list.add(matrix[(m-1)-i][j]);
}
for (int j = (m-1)-(i+1); j >= i+1 && (n-1-i) != i; j--) {
list.add(matrix[j][i]);
}
i++;
}
return list;
}
作者:liao-tian-yi-jian
链接:https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-liao-tian-yi-jian/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
221. 最大正方形 2
dp[i][j]
标识以i,j为右下角的最大的正方形的边长
class Solution {
public int maximalSquare(char[][] matrix) {
//动态规划:
int maxLen = 0;
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return maxLen;
}
int row = matrix.length;
int col = matrix[0].length;
int[][] dp = new int[row][col];
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (matrix[i][j] == '1'){
if(i == 0 || j == 0) dp[i][j] = 1;
else{
dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1])+1;
}
maxLen = Math.max(maxLen, dp[i][j]);
}
}
}
return maxLen * maxLen;
}
}
23. 合并K个排序链表 2
只需要保证加的时候不为空即可,无需判断取的时候是否为空
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode d = new ListNode(-1);
ListNode res = d;
Queue<ListNode> pq = new PriorityQueue<>((l1,l2)->l1.val-l2.val);
for (int i = 0; i < lists.length; i++) {
if(lists[i] != null)
pq.offer(lists[i]);
}
while(!pq.isEmpty()){
ListNode t = pq.poll();
d.next = t;
d = t;
if(t.next != null){
pq.offer(t.next);
}
}
return res.next;
}
}
83. 删除排序链表中的重复元素 2
class Solutison {
public ListNode deleteDuplicates(ListNode head) {
ListNode res = head;
while(head != null && head.next != null){
if(head.val == head.next.val){
head.next = head.next.next;
}else{
head = head.next;
}
}
return res;
}
}
70. 爬楼梯 2
剑指 Offer 61. 扑克牌中的顺子 2
最大牌 - 最小牌 < 5 则可构成顺子
666啊。
class Solution {
public boolean isStraight(int[] nums) {
int joker = 0;
Arrays.sort(nums); // 数组排序
for(int i = 0; i < 4; i++) {
if(nums[i] == 0) joker++; // 统计大小王数量
else if(nums[i] == nums[i + 1]) return false; // 若有重复,提前返回 false
}
return nums[4] - nums[joker] < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/solution/mian-shi-ti-61-bu-ke-pai-zhong-de-shun-zi-ji-he-se/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
32. 最长有效括号 2
非常好的一个思路:
- 在栈底放入-1这个边界
public class Solution {
public int longestValidParentheses(String s) {
int maxans = 0;
Stack<Integer> stack = new Stack<>();
stack.push(-1);
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stack.push(i);
} else {
stack.pop();
if (stack.empty()) {
stack.push(i);//说明弹出前栈里只有一个值,除了)就是-1
} else {
maxans = Math.max(maxans, i - stack.peek());//逐步尝试更新
}
}
}
return maxans;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 42. 连续子数组的最大和 2
class Solution {
public int maxSubArray(int[] nums) {
int res = nums[0];
int pre = nums[0];
for(int i = 1; i < nums.length; i++) {
pre = nums[i] + Math.max(pre, 0);
res = Math.max(res, pre);
}
return res;
}
}
415. 字符串相加 2
要让我写,肯定要三个循环,类似两个链表合并那种。
有没有想起来寻找两个链表交点的那道题?也是直接一个循环,使用三目运算符无痛替换。
有时候有些题套路比思路重要
编程八股文奥利给!
class Solution {
public String addStrings(String num1, String num2) {
StringBuilder res = new StringBuilder("");
int i = num1.length() - 1, j = num2.length() - 1, carry = 0;
while(i >= 0 || j >= 0){
int n1 = i >= 0 ? num1.charAt(i) - '0' : 0;
int n2 = j >= 0 ? num2.charAt(j) - '0' : 0;
int tmp = n1 + n2 + carry;
carry = tmp / 10;
res.append(tmp % 10);
i--; j--;
}
if(carry == 1) res.append(1);
return res.reverse().toString();
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/add-strings/solution/add-strings-shuang-zhi-zhen-fa-by-jyd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
41. 缺失的第一个正数 2
class Solution {
public int firstMissingPositive(int[] nums) {
int n = nums.length;
for (int i = 0; i < n; i++) {
// 将某个元素i放到i-1位置去。
// nums[i] == nums[nums[i] - 1]
while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {
swap(nums, i, nums[i] - 1);
}
}
for (int i = 0; i < n; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return n + 1;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
704. 二分查找 2
我的二分模板全天下第一嘿嘿。
- 两边闭
- <
- 查找左和右边界时中点分别靠左和右
- 最后要判断
class Solution {
public int search(int[] nums, int target) {
int pivot, left = 0, right = nums.length - 1;
while (left < right) {
pivot = left + (right - left) / 2;
if (nums[pivot] == target) return pivot;
if (target < nums[pivot]) right = pivot - 1;
else left = pivot + 1;
}
return nums[left] == target ? left : -1;
}
}
958. 二叉树的完全性检验 2
思路太棒了,层序遍历,判断前一个是null而后一个不是null即可。
class Solution {
public boolean isCompleteTree(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
TreeNode prev = root;
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.remove();
if (prev == null && node != null)
return false;
if (node != null) {
queue.add(node.left);
queue.add(node.right);
}
prev = node;
}
return true;
}
}
作者:yuanyb
链接:https://leetcode-cn.com/problems/check-completeness-of-a-binary-tree/solution/hen-jian-dan-de-si-lu-dai-ma-hen-jian-ji-by-yuanyb/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
后端 69. x 的平方根 2
注意不要用
mid * mid == x
这样的判断条件,容易溢出
我太喜欢我的二分模板了,想和它开房。
class Solution {
public int mySqrt(int x) {
// 二分查找左边界
int le = 1;
int ri = x;
while (le < ri){
int mid = (le + ri) / 2;
if(mid == x / mid) return mid;
else if(mid > x / mid) ri = mid;
else le = mid + 1;
}
return le * le == x ? le : le - 1;
}
}
114. 二叉树展开为链表 2
class Solution {
public void flatten(TreeNode root) {
dfs(root);
}
// 返回值分别是两个链表的尾部节点。
private TreeNode dfs(TreeNode root) {
if (root == null) return root;
TreeNode ltail = dfs(root.left);
TreeNode rtail = dfs(root.right);
if(ltail != null){
ltail.right = root.right;
root.right = root.left;
root.left = null;
}
// 右侧子树的链表不空,返回这个
if(rtail != null) return rtail;
// 左侧子树的链表不空,返回这个
if(ltail != null) return ltail;
return root;
}
}
这个思路非常好,使用共有节点。
class Solution {
//先序遍历,原地展开
private TreeNode pre = null;
public void flatten(TreeNode root) {
if (root == null)
return;
flatten(root.right);
flatten(root.left);
root.right = pre;
root.left = null;
pre = root;
}
}