数组
全排列重复
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permute = function(nums) {
let res = [],path=[],used=[]
track()
function track(){
if(path.length === nums.length){
res.push(Array.from(path))
}
for(let i = 0;i < nums.length;i++){
if(used[i]){
continue
}
used[i] = true
path.push(nums[i])
track()
used[i] = false
path.pop(nums[i])
}
}
return res
};
全排列不重复
var permuteUnique = function (nums) {
let res = [], path = []
nums.sort((x, y) => x - y);
function track(nums, k, used) {
if (nums.length === path.length) {
res.push(Array.from(path))
return
}
for (let i = 0; i < k; i++) {
//当前元素使用过或者当前元素的值等于前一个元素的值,前一个元素也使用过则跳过
if (used[i] || i > 0 && nums[i] === nums[i - 1] && used[i - 1] === true) continue
path.push(nums[i])
used[i] = true
track(nums, k, used)
used[i] = false
path.pop()
}
}
track(nums, nums.length, [])
return res
};
电话号码组合
var letterCombinations = function (digits) {
let map = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"]
let path = [], res = []
if(digits.length === 0) return []
if(digits.length === 1) return map[digits].split("");
function track(a) {
if (path.length === digits.length) {
res.push(path.join(""));
return;
}
for (const v of map[digits[a]]) {
path.push(v);
track(a + 1);
path.pop();
}
}
track(0)
return res
};
组合问题
var combine = function(n, k) {
let res = [],path = []
function track(start){
if(k === path.length){
res.push(Array.from(path))
}
for(let i = start;i <= n;i++){
//没找到一个push进去
path.push(i)
//从i+1找
track(i+1)
//上级找完pop
path.pop()
}
}
track(1)
return res
};
组合求和可重复
var combinationSum = function(candidates, target) {
let res = [],path = []
function track(start,sum){
if(sum > target){
return
}
if(sum === target){
res.push(Array.from(path))
}
for(let i = start;i < candidates.length;i++){
path.push(candidates[i])
track(i,sum+candidates[i])
path.pop()
}
}
// 最开始可选的数是从第0项开始的,传入一个空集合,sum也为0
track(0,0)
return res
};
组合求和不重复
const combinationSum2 = (candidates, target) => {
candidates.sort((a,b) => a - b ); // 升序排序
const res = [];
const dfs = (start, temp, sum) => { // start是索引 当前选择范围的第一个
if (sum >= target) { // 爆掉了,不用继续选了
if (sum == target) { // 满足条件,加入解集
res.push(temp.slice()); // temp是引用,所指向的内存后续还要操作,所以拷贝一份
}
return; // 结束当前递归
}
for (let i = start; i < candidates.length; i++) { // 枚举出当前的选择
// 当前选项和左邻选项一样,跳过
if (i - 1 >= start && candidates[i - 1] == candidates[i]) {
continue;
}
temp.push(candidates[i]); // 作出选择
dfs(i + 1, temp, sum + candidates[i]); // 基于该选择,继续选择,递归
temp.pop(); // 上面的递归结束,撤销选择,回到选择前的状态,切入另一分支
}
};
dfs(0, [], 0);
return res;
};
组合数三
const combinationSum3 = (k, n) => {
const res = [];
// 基于当前已选的comb数组(和为sum),在数start到数9中继续选
const dfs = (start, comb, sum) => {
if (comb.length == k) { // 选够k个数 结束递归
if (sum == n) { // 组合中数之和等于n
res.push(comb.slice()); // 将它的拷贝加入解集
}
return;
}
for (let i = start; i <= 9; i++) { // 枚举出所有的选择(选项)
comb.push(i); // 作出一个选择i
dfs(i + 1, comb, sum + i); // 基于该选择i,往下递归
comb.pop(); // 撤销这个选择
}
};
dfs(1, [], 0); // 入口
return res;
};
括号生成
var generateParenthesis = function (n) {
const res = [];
const dfs = (lRemain, rRemain, str) => { // 左右括号所剩的数量,str是当前构建的字符串
if (str.length == 2 * n) { // 字符串构建完成
res.push(str); // 加入解集
return; // 结束当前递归分支
}
if (lRemain > 0) { // 只要左括号有剩,就可以选它,然后继续做选择(递归)
dfs(lRemain - 1, rRemain, str + "(");
}
if (lRemain < rRemain) { // 右括号比左括号剩的多,才能选右括号
dfs(lRemain, rRemain - 1, str + ")"); // 然后继续做选择(递归)
}
};
dfs(n, n, ""); // 递归的入口,剩余数量都是n,初始字符串是空串
return res;
};
分割回文串
var partition = function (s) {
const res = [];
function dfs(temp, start) {
if (start == s.length) {
res.push(temp.slice());
return;
}
for (let i = start; i < s.length; i++) {
if (isPali(s, start, i)) {
temp.push(s.substring(start, i + 1));
dfs(temp, i + 1);
temp.pop();
}
}
}
dfs([], 0);
return res;
};
function isPali(s, l, r) {
while (l < r) {
if (s[l] != s[r]) {
return false;
}
l++;
r--;
}
return true;
}
子集
var subsets = function(nums) {
let res = [],path = []
function track(start){
res.push(Array.from(path))
for(let i = start;i < nums.length;i++){
path.push(nums[i])
track(i+1)
path.pop(nums[i])
}
}
track(0)
return res
};
三数之和
var threeSum = function (nums) {
let res = []
nums.sort((x, y) => x - y)
for (let i = 0; i < nums.length - 2; i++) {
let left = i + 1, right = nums.length - 1
if (nums[0] > 0) {
break
}
if (i - 1 >= 0 && nums[i] === nums[i - 1]) {
continue
}
while (left < right) {
let sum = nums[i] + nums[left] + nums[right]
if (sum > 0) {
right--
} else if (sum < 0) {
left++
} else {
res.push([nums[i],nums[left],nums[right]])
while(left < right && nums[right] === nums[--right]);
while(left < right && nums[left] === nums[++left]);
}
}
}
return res
};
最接近的三数之和
var threeSumClosest = function (nums, target) {
if(nums.length === 3) return nums[0]+nums[1]+nums[2]
nums= nums.sort((a,b)=> a - b)
let res
let min = Infinity
for (let i = 0; i <= nums.length - 3; i++) {
let basic = nums[i]
let left = i + 1
let right = nums.length - 1
while (left < right) {
let sum = basic + nums[left] + nums[right] //三数之和
let diff = Math.abs(sum - target) //最小查
if (diff < min) {
min = diff
res = sum
}
if (sum < target) {
left++
} else {
right--
}
}
}
return res
};
旋转排序数组-无重复
const search = (nums, target) => {
let [left, right] = [0, nums.length - 1];
while (left <= right) {
const mid = (left + right) >> 1;
if (nums[mid] === target) return mid;
if (nums[left] < nums[mid]) {
// 左边是升序的
if (nums[left] <= target && target <= nums[mid]) {
// target在升序的里面
right = mid - 1;
} else {
// target不在升序的里面
left = mid + 1;
}
} else {
// 右边升序
if (nums[mid] <= target && target <= nums[right]) {
// target在升序的里面
left = mid + 1;
} else {
// target不在升序的里面
right = mid - 1;
}
}
}
return nums[left + 1] === target ? left + 1 : -1;
};
旋转排序数组有重复
var search = function(nums, target) {
const n = nums.length;
if (n === 0) {
return false;
}
if (n === 1) {
return nums[0] === target;
}
let l = 0, r = n - 1;
while (l <= r) {
const mid = Math.floor((l + r) / 2);
if (nums[mid] === target) {
return true;
}
if (nums[l] === nums[mid] && nums[mid] === nums[r]) {
++l;
--r;
} else if (nums[l] <= nums[mid]) {
if (nums[l] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return false;
};
螺旋矩阵
var spiralOrder = function (matrix) {
if (matrix.length == 0) return []
const res = []
let top = 0, bottom = matrix.length - 1, left = 0, right = matrix[0].length - 1
const size = matrix.length * matrix[0].length
while (res.length !== size) { // 仍未遍历结束
for (let i = left; i <= right; i++) res.push(matrix[top][i])
top++
for (let i = top; i <= bottom; i++) res.push(matrix[i][right])
right--
if (res.length === size) break // 遍历结束
for (let i = right; i >= left; i--) res.push(matrix[bottom][i])
bottom--
for (let i = bottom; i >= top; i--) res.push(matrix[i][left])
left++
}
return res
};
旋转图像
var rotate = function(matrix) {
const n = matrix.length;
// 水平翻转
for (let i = 0; i < Math.floor(n / 2); i++) {
for (let j = 0; j < n; j++) {
[matrix[i][j], matrix[n - i - 1][j]] = [matrix[n - i - 1][j], matrix[i][j]];
}
}
// 主对角线翻转
for (let i = 0; i < n; i++) {
for (let j = 0; j < i; j++) {
[matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
}
}
};
砖墙
var leastBricks = function (wall) {
let map = new Map() //存放缝隙
let height = wall.length
let res = height
for (let i = 0; i < height; i++) {
let sum = 0
//每次层的缝隙全部放进来
for (let item of wall[i]) {
sum += item
if (map.has(sum)) {
map.set(sum,map.get(sum)+1)
} else {
map.set(sum,1)
}
}
//删除每一层最右边的缝隙
map.delete(sum)
sum = 0
}
//找到缝隙最多的
for(let [x,y] of map){
res = Math.min(res,height-y)
}
return res
};
合并区间
var merge = function(intervals) {
let res = []
intervals.sort((x,y)=>x[0]-y[0])
let start = intervals[0]
for(let i = 0;i < intervals.length;i++){
let cur = intervals[i]
if(start[1] >= cur[0]){
start[1] = Math.max(start[1],cur[1])
}else{
res.push(start)
start = cur
}
}
res.push(start)
return res
};
js排序方式
let arr = [30,10,111,35,1899,50,45]
arr.sort((x,y)=>{
return x-y
})
console.log(arr)
let arr = [[2,1],[2,6],[1,5],[1,9],[3,1]]
arr.sort((x,y)=>{
if(x[0] === y[0]){
return x[1] - y[1]
}else{
return x[0] - y[0]
}
})
//[ [ 1, 5 ], [ 1, 9 ], [ 2, 1 ], [ 2, 6 ], [ 3, 1 ] ]
console.log(arr)
快排
let arr = [5,6,1,2,3,5,8,9,1,55]
function quickSort(arr,left,right){
if(left < right){
let positions = position(arr,left,right)
quickSort(arr,left,positions-1)
quickSort(arr,positions + 1,right)
}
}
function position(arr,left,right){
let tmp = arr[left]
while(left < right){
while(left < right && arr[right] >= tmp){
right --;
}
arr[left] = arr[right]
while(left < right && arr[left] <= tmp){
left ++;
}
arr[right] = arr[left]
}
arr[left] = tmp
return left
}
quickSort(arr,0,arr.length-1)
console.log(arr)
topK
topK快排思路大
/**
* @param {number[]} arr
* @param {number} k
* @return {number[]}
*/
var getLeastNumbers = function(arr, k) {
quicksort(arr,0,arr.length-1,k)
return arr.splice(0,k)
};
function quicksort(arr,left,right,k){
if(left < right){
let position = getPos(arr,left,right,k);
if(position == k){
return
}else if(k < position){
quicksort(arr,left,position-1,k)
}else{
quicksort(arr,position+1,right,k)
}
}
}
function getPos(arr,left,right,k){
let tmp = arr[left]
while(left < right){
while(left < right && arr[right] >= tmp){
right--
}
arr[left] = arr[right]
while(left < right && arr[left] <= tmp){
left++
}
arr[right] = arr[left]
}
arr[left] = tmp
return left
}
topK堆排序思路大
topk大
var getLeastNumbers = function (arr, k) {
return headSort(arr, k)
};
function headSort(arr, k) {
let len = arr.length
for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {
adjust(arr, i, len)
}
// for (let j = arr.length - 1; j >= 0; j--) {
// swap(arr, 0, j)
// adjust(arr, 0, j)
// }
let resultArray = []
for(let i = 1; i <= k; i++){
resultArray.push(arr[0])
swap(arr, 0, len - i)
adjust(arr, 0, len - i)
}
return resultArray
}
function adjust(arr, i, len) {
let tmp = arr[i]
for (let m = 2*i+1;m < len;m = 2*m+1) {
if(m+1 < len && arr[m] < arr[m+1]){
m++
}
if (arr[m] > arr[i]) {
arr[i] = arr[m]
i = m
} else {
break
}
arr[i] = tmp
}
}
function swap(arr, i, j) {
let tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
}
小镇法官
var findJudge = function(n, trust) {
if(n == 1) return 1
let result = new Array(n+1).fill(0)
//根据下标记录每个人的信任次数
for(let i = 0;i < trust.length;i++){
result[trust[i][0]]--
result[trust[i][1]]++
}
//信任次数 = n-1的人的下标就是
for(let i = 0;i < result.length;i++){
if(result[i] === n-1) return i
}
return -1
};
旋转数组
const search = (nums, target) => {
let [left, right] = [0, nums.length - 1];
while (left <= right) {
const mid = (left + right) >> 1;
if (nums[mid] === target) return mid;
if (nums[left] < nums[mid]) {
// 左边是升序的
if (nums[left] <= target && target <= nums[mid]) {
// target在升序的里面
right = mid - 1;
} else {
// target不在升序的里面
left = mid + 1;
}
} else {
// 右边升序
if (nums[mid] <= target && target <= nums[right]) {
// target在升序的里面
left = mid + 1;
} else {
// target不在升序的里面
right = mid - 1;
}
}
}
return nums[left + 1] === target ? left + 1 : -1;
};
非递减数列
/**
* @param {number[]} nums
* @return {boolean}
*/
var checkPossibility = function(nums) {
let count=0
for(let i=0;i<=nums.length-2;i++){
//上一个值、当前值、下一个值设为before、cur、next
let before=nums[i-1], cur=nums[i],next=nums[i+1];
// 当next>=before,为了不破坏下一次判断,我们令cur=next,这样cur既大于等于before,也不会影响下一个值
//当next<before,那我们就不能修改cur值了,因为这样会使得cur<before,因此我们令next=cur,然后在下次循环中判断可不可行
if(next<cur){
if(next>=before||before===undefined){
}else{
nums[i+1]=cur;
}
count++;
}
if(count>1){
return false;
}
}
return true;
};
二分查找有重复数的有序数组
function search( nums , target ) {
let left = 0,right = nums.length-1
let res = -1
while(left <= right){
let mid = (left + right) >> 1
if(nums[mid] === target){
res = mid
right = mid - 1
}else if(nums[mid] < target){
left = mid +1
}else{
right = mid -1
}
}
return res
}
只出现一次的数
var singleNumber = function(nums) {
let ans = 0;
for(const num of nums) {
ans ^= num;
}
return ans;
};
分糖果
var distributeCandies = function(candyType) {
candyType.sort((x,y)=>x-y)
let count = 1
for(let i = 1;i < candyType.length;i++){
if(candyType[i] !== candyType[i-1] && count < Math.floor(candyType.length/2)){
count++
}
}
return count
};
数组中超过一半的数
var majorityElement = function(nums) {
let count = 1;
let majority = nums[0];
for(let i = 1; i < nums.length; i++) {
if (count === 0) {
majority = nums[i];
}
if (nums[i] === majority) {
count ++;
} else {
count --;
}
}
return majority;
};
六个数最大时间
function getTime(time) {
let flag = 'invalid'
let result = []
let data1 = getDataOfLocation(list, 3);
if (data1 != -1) {
list.splice(list.indexOf(data1), 1)
result.push(data1)
} else {
return flag;
}
//如果第一位是2,那么第二位则不能超过4
if (result[0] == '2') {
//第二位
let data2 = getDataOfLocation(list, 4);
if (data2 != -1) {
// 按照元素删除
list.splice(list.indexOf(data2), 1)
result.push(data2);
} else {
return flag;
}
// 否则,第一位可能是0或者1,这样第二位可以是0-9,即小于10
} else {
//第二位
let data2_t = getDataOfLocation(list, 10);
if (data2_t != -1) {
list.splice(list.indexOf(data2_t), 1)
result.push(data2_t);
} else {
return flag;
}
}
//第三位,分钟最大是59,即小于6
let data3 = getDataOfLocation(list, 6);
if (data3 != -1) {
list.splice(list.indexOf(data3), 1)
result.push(data3);
} else {
return flag;
}
//第四位,0-9
let data4 = getDataOfLocation(list, 10);
if (data4 != -1) {
list.splice(list.indexOf(data4), 1)
result.push(data4);
} else {
return flag;
}
//第五位
let data5 = getDataOfLocation(list, 6);
if (data5 != -1) {
list.splice(list.indexOf(data5), 1)
result.push(data5);
} else {
return flag;
}
//最后一位
if (getDataOfLocation(list, 10) != -1) {
result.push(getDataOfLocation(list, 10));
} else {
return flag;
}
return result
}
function getDataOfLocation(list, standard) {
let arr = list.filter((x) => {
return x < standard
})
if (arr.length === 0) {
return -1
}
let max = Math.max(...arr)
return max
}
let list = [0, 2, 3, 0, 5, 6]
getTime(list)
删除有序数组中的重复数
var removeDuplicates = function(nums) {
let left = 1,right = 1
while(right < nums.length){
if(nums[right] !== nums[right-1]){
nums[left] = nums[right]
left++
}
right++
}
return left
};
移除数组中指定的元素
var removeElement = function(nums, val) {
let left = 0
for(let i = 0;i < nums.length;i++){
if(nums[i] !== val){
nums[left] = nums[i]
left ++
}
}
return left
};
数组+1
var plusOne = function(digits) {
for (let i = digits.length - 1; i >= 0; i--) {
if (digits[i] !== 9) {
digits[i]++;
// 不为9,加1后直接返回
return digits;
} else {
// 当前位为9时,把当前位置为0,继续循环会进行进位操作
digits[i] = 0;
}
}
// 当遍历结束了,且数组是99、999... 等特殊情况,在开头添加1
digits.unshift(1);
return digits;
};
数组形式的整数加法
/**
* @param {number[]} num
* @param {number} k
* @return {number[]}
*/
var addToArrayForm = function (num, k) {
let i = num.length - 1
let flag = 0
let res = []
while (i >= 0 || k !== 0) {
let x = num[i] === undefined ? 0 : num[i]
let y = k % 10
let sum = flag + x + y
res.unshift(sum % 10)
flag = Math.floor(sum / 10)
k = Math.floor(k / 10)
i--
}
if (flag === 1) {
res.unshift(1)
}
return res
};
兄弟单词
let train = ['abc' ,'bca' ,'cab']
let test = 'abc'
function isBrother(a,b){
if(a === b){
return false
}else{
console.log(a.split('').sort(),b.split('').sort())
if(a.split('').sort().join('') === b.split('').sort().join('')){
return true
}else{
return false
}
}
}
let count = 0
for(let i = 0;i < train.length;i++){
if(isBrother(train[i],test)){
count ++
}
}
console.log(count)
扑克牌中的顺子
class Solution {
public boolean isStraight(int[] nums) {
Set<Integer> repeat = new HashSet<>();
int max = 0, min = 14;
for(int num : nums) {
if(num == 0) continue; // 跳过大小王
max = Math.max(max, num); // 最大牌
min = Math.min(min, num); // 最小牌
if(repeat.contains(num)) return false; // 若有重复,提前返回 false
repeat.add(num); // 添加此牌至 Set
}
return max - min < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
}
}
根据身高重建队列
/**
* @param {number[][]} people
* @return {number[][]}
*/
var reconstructQueue = function (people) {
// 将people按身高从大到小排序,如果身高一样则将前面高于自己人数小的人放在前面
people.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : b[0] - a[0])
// 创建新数组 ans
let ans = []
for (let i = 0; i < people.length; i++) {
// 挨个根据前面高于自己人数插入到ans里
// 因为people已按照身高排序,所以某个人被插入到ans里时,所有比他高的都已经在ans里了
// 而身高比他矮的人怎样插入到ans里都不影响前面高于他的人数
// 所以这样得到的数组就是符合我们要求的队列
ans.splice(people[i][1],0,people[i])
}
return ans
};
单词的压缩编码
/**
* @param {string[]} words
* @return {number}
*/
/**
* 暴力破解:
* 1. 先根据单词长度排序(降序)
* 2. 在根据indexOf判断,得到压缩后的S,返回S的长度
*/
var minimumLengthEncoding = function(words) {
let S = ''
words = words.sort( (a,b)=>b.length - a.length)
for( let i = 0; i < words.length; i++ ){
const word = words[i]
const index = S.indexOf( word + '#' )
if( !~index ) {
S += `${word}#`
}
}
return S.length
};