有不含有重复数字的数组构造二叉树_GitHub - Baoyubushiyu/LeetCode: Algorithms Exercise: LeetCode Problems, LeetCode We...

LeetCode总结

所有的题目总结均在每一个package的README中

目录

搜索(回溯、BFS、DFS):

回溯:数独、N皇后、37、51、79、93、[212、301]

BFS:矩阵、单词变换

排列、组合、分割、子集:四大类问题,常用回溯、DFS解决

图的搜索:DFS、BFS、并查集、Flood

并查集(TODO)

二分查找:

g 函数,利用边界

K th 问题

旋转数组

双指针:

左右指针:数组(或字符串)问题,二分查找也算是双指针,三数之和,Sunday算法

快慢指针:链表中环的问题

滑动窗口:更新窗口

链表:

链表的基本操作

旋转(K组旋转,奇偶旋转)、拆分

归并

判断环(快慢指针)

二叉树:

遍历

深度、层次

树的结构相关

树的路径相关,递归的过程之中不断更新全局变量

剪枝

二叉搜索树

数学:

概率:洗牌算法、蓄水池抽样、蒙特卡洛

数论:素数,最小公倍数,最大公约数

位运算:异或,与的巧妙用法

特殊的数:有效数字(状态机),第n个丑数,平方数(DP解法),回文数

数字的转化:溢出检测、模拟运算(时刻注意溢出)、罗马、字符转成数字;分数转小数

其他:Pow()快速幂算法,众数投票法

动态规划

排序

数据结构

单调栈

单调队列

分治

贪心

心法宝典

递归要素:开头-判断边界(退出条件);中间-进行相关的计算、缩小范围递归(经常用到全局变量哦);结尾-返回值(还要学会如何利用返回值)

反转链表:迭代写法返回prev,递归写法每次考虑两个节点(返回值是前递归的返回值)

采样:n个数随机采样m个,knuth采样:对于每个下标[0,n) 每次n--, 若rand()%n < m时才m--

Shuffle:knuth Shuffle,i从后往前,每次从[0,i]选择一个位置与i交换

DP: DP 就是填表法,首先明确初始值(并且要明确这个值是什么值),然后要明确填表的顺序,最后是如何填(状态转移方程)。

使用移位运算一定要注意运算符的优先级

双指针

双指针主要分为三类:左右(一般是数组或者字符串,经典的有三数之和和四数之和),快慢指针(一般是和链表环有关系),滑动窗口

1. 序列

无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。注意区分子串与子序列区别

// [i, j), 无重复的时候j++, 有重复的时候i++

public int lengthOfLongestSubstring(String s) {

Set set = new HashSet<>(); // int[] dic = new int[256];

int i = 0, j = 0;

int ret = 0;

while (j < s.length() && i <= j) {

// 是否存在重复字符

if (!set.contains(s.charAt(j))) {

set.add(s.charAt(j));

j++;

ret = Math.max(ret, j-i); // 注意此处没+1,因为j先自增了

} else {

set.remove(s.charAt(i));

i++;

}

}

return ret;

}

盛最多水的容器

不能倾斜容器,且 n (数组的长度)的值至少为 2。

思路:我们要做的就是保证宽度最大的情况下,高度最大; 一开始宽度最大,然后逐步减少宽度;这个时候要不断的去更新高度,使得高度尽量的大,如何移动较大的一端,那么面积肯定是减小的;移动较小的那一个端,面积有可能增大

public int maxArea(int[] height) {

int i = 0, j = height.length-1;

int maxValue = 0;

while (j - i >= 1) {

System.out.println((j-i) * Math.min(height[i], height[j]));

maxValue = Math.max(maxValue, (j-i) * Math.min(height[i], height[j]));

if (height[i] < height[j]) {

i++;

} else {

j--;

}

}

return maxValue;

}

三数之和

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a, b, c, 使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

// 难点: 三数之和 -> 两数之和(哈希、排序+双指针); 排除重复

// 排序+双指针 : valtarget时 high--; val==target时low++ & high--

// 如何跳过重复

public List> threeSum(int[] nums) {

List> ret = new LinkedList<>();

Integer iPre = null;

Arrays.sort(nums);

for (int i = 0; i < nums.length-2; i++) {

if (nums[i] > 0) break;

int j = i+1, k = nums.length-1, sum = 0 - nums[i];

Integer jPre = null, kPre = null;

if (iPre != null && iPre == nums[i]) continue; // 去重

iPre = nums[i];

while (j < k) {

if (nums[j] + nums[k] < sum) {

j++;

}

else if (nums[j] + nums[k] > sum) {

k--;

} else {

if (jPre == null || (jPre != nums[j] && kPre != nums[k])) {

ret.add(Arrays.asList(nums[i], nums[j], nums[k]));

}

jPre = nums[j];

kPre = nums[k];

j++;

k--;

}

}

}

return ret;

}

最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

// 本题假定只有 一个答案,所以不用去重了

// 和第15题思路一模一样

public int threeSumClosest(int[] nums, int target) {

// nums.length > 3

Arrays.sort(nums);

int ret = nums[0]+nums[1]+nums[2];

for (int i = 0; i < nums.length-2; i++) {

int j = i+1, k = nums.length-1, sum;

while (j < k) {

sum = nums[i] + nums[j] + nums[k];

if (Math.abs(sum-target) < Math.abs(ret-target)) {

ret = sum;

}

if (sum == target) {

return target;

} else if (sum > target) {

k--;

} else {

j++;

}

}

}

return ret;

}

四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d , 使得 a + b + c + d 的值与 target 相等? 找出所有满足条件且不重复的四元组。和第15题一个思路。

// 双指针 + 去重

public List> fourSum(int[] nums, int target) {

List> ret = new LinkedList<>();

Integer aPre = null;

Arrays.sort(nums);

for (int a = 0; a < nums.length-3; a++) {

if (nums[a] > 0 && nums[a] > target) break; // 注意一定要加nums[a] > 0

if (aPre != null && aPre == nums[a]) continue;

aPre = nums[a];

Integer bPre = null;

for (int b = a+1; b < nums.length-2; b++) {

if (nums[b] > 0 && nums[a] + nums[b] > target) break;

if (bPre != null && bPre == nums[b]) continue; // 去重

bPre = nums[b];

int c = b+1, d = nums.length-1, sum = target - (nums[a] + nums[b]);

Integer cPre = null, dPre = null;

while (c < d) {

if (nums[c] + nums[d] < sum) c++;

else if (nums[c] + nums[d] > sum) d--;

else {

if (cPre == null || (cPre != nums[c] && dPre != nums[d])) {

ret.add(Arrays.asList(nums[a], nums[b], nums[c], nums[d]));

}

cPre = nums[c];

dPre = nums[d];

c++;

d--;

}

}

}

}

return ret;

}

删除排序数组的重复项

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。不需要考虑数组中超出新长度后面的元素。

public int removeDuplicates(int[] nums) {

int i = 0, len = nums.length;

for (int j = 0; j < len; j++) {

if (j+1 < len && nums[j] != nums[j+1]) {

nums[i++] = nums[j];

}

}

if (len > 0) nums[i++] = nums[len-1];

return i;

}

移除元素

原地移除元素,分很多种情况。

// 2. 当要移动的很多时候

public int removeElement(int[] nums, int val) {

if (nums == null || nums.length == 0) return 0;

int i = 0, j = nums.length-1;

while (i <= j) {

while (i <= j && nums[i] != val) i++;

while (i <= j && nums[j] == val) j--;

if (j > i) nums[i++] = nums[j--];

}

// if (nums[i] == val) return i;

return j+1;

}

// 2.2 只和最后一个元素交换

public int removeElement2(int[] nums, int val) {

if (nums == null || nums.length == 0) return 0;

int i = 0, n = nums.length;

while (i < n) {

if (nums[i] == val) {

nums[i] = nums[n-1];

n--;

} else {

i++;

}

}

// if (nums[i] == val) return i;

return n;

}

模式匹配

不要求掌握较难的KMP算法,掌握Sunday算法。

// Sunday算法:如果当前窗口不匹配,比较窗口下一个字符串;下一个字符串在shift数组中的位置,就是窗口要偏移的距离

// 先计算shift数组 every char : len(needle) - max(char) otherwise: len+1

public int strStr(String haystack, String needle) {

// 使用 HashMap 实现shift数组

HashMap shiftMap = new HashMap<>();

int len = needle.length();

for (int i = 0; i < len; i++) {

Character character = needle.charAt(i);

if (!shiftMap.containsKey(character)) {

for (int j = len-1; j >= 0; j--) {

if (needle.charAt(j) == character) {

shiftMap.put(character, len-j);

break;

}

}

}

}

int p = 0;

while (p + len <= haystack.length()) {

int i;

for (i = 0; i < len; i++) {

if (haystack.charAt(p+i) != needle.charAt(i)) break;

}

if (i == len) return p;

else if (p+len == haystack.length()) return -1;

else p += shiftMap.getOrDefault(haystack.charAt(p+len), len+1);

}

return -1;

}

颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。使用一趟扫描。

private void swap(int[] nums, int i, int j) {

if (nums[i] == nums[j]) return;

int temp = nums[i];

nums[i] = nums[j];

nums[j] = temp;

}

public void sortColors(int[] nums) {

int p0 = 0, p2 = nums.length-1;

int cur = 0;

while (cur <= p2) {

if (nums[cur] == 0) swap(nums, cur++, p0++);

else if (nums[cur] == 2) swap(nums, cur, p2--);

else cur++;

}

}

合并两个有序数组

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。初始化 nums1 和 nums2 的元素数量分别为 m 和 n。你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

public void merge(int[] nums1, int m, int[] nums2, int n) {

int i = m-1, j = n-1, k = m+n-1;

while (i >= 0 && j >= 0) {

if (nums1[i] < nums2[j]) {

nums1[k--] = nums2[j--];

} else {

nums1[k--] = nums1[i--];

}

}

while (j >= 0) {

nums1[k--] = nums2[j--];

}

}

搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。

该矩阵具有以下特性:每行的元素从左到右升序排列。每列的元素从上到下升序排列。

public boolean searchMatrix(int[][] matrix, int target) {

if (matrix.length == 0 || matrix[0].length == 0) return false;

int m = matrix.length, n = matrix[0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值