add: 只出现一次的数字等

This commit is contained in:
2019-03-10 16:43:04 +08:00
committed by yi-ge
parent 930ff1be11
commit 8239e7afd5
106 changed files with 7978 additions and 0 deletions

34
src/array/01-matrix.js Normal file
View File

@ -0,0 +1,34 @@
/**
* @param {number[][]} matrix
* @return {number[][]}
*/
export const updateMatrix = function (matrix) {
if (matrix.length === 0) return []
const m = matrix.length
const n = matrix[0].length
// 左上 -> 右下
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (matrix[i][j] !== 0) {
matrix[i][j] = m + n
if (i > 0) matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j])
if (j > 0) matrix[i][j] = Math.min(matrix[i][j - 1] + 1, matrix[i][j])
}
}
}
// 右下 -> 左上
for (let i = m - 1; i >= 0; i--) {
for (let j = n - 1; j >= 0; j--) {
// distance
if (matrix[i][j] !== 0) {
if (j < n - 1) matrix[i][j] = Math.min(matrix[i][j], matrix[i][j + 1] + 1)
if (i < matrix.length - 1) matrix[i][j] = Math.min(matrix[i][j], matrix[i + 1][j] + 1)
}
}
}
return matrix
}

View File

@ -0,0 +1,14 @@
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function (prices) {
let profit = 0
for (let n = 1; n < prices.length; n++) {
if (prices[n] > prices[n - 1]) profit += prices[n] - prices[n - 1]
}
return profit
}
export default maxProfit

View File

@ -0,0 +1,27 @@
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
export const search = function (nums, target) {
if (!nums || nums.length === 0) return -1
let start = 0
let end = nums.length
while (start < end) {
const mid = Math.floor(start + (end - start) / 2)
if (target === nums[mid]) {
end = mid
} else if (target < nums[mid]) {
end = mid - 1
} else {
start = mid + 1
}
}
if (target === nums[start]) {
return start
}
return -1
}

19
src/array/bubble-sort.js Normal file
View File

@ -0,0 +1,19 @@
// 冒泡排序
// 平均时间复杂度 O(n * n) 最好情况 O(n),最坏情况 On * n
// 空间复杂度 O(1)
// 稳定
export default (arr) => {
for (let n = 0, len = arr.length - 1, down = true; n < len; n++) {
for (let i = 0, iLen = len - n; i < iLen; i++) {
if (arr[i + 1] < arr[i]) {
const tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
down = false
}
}
if (down) break
}
return arr
}

View File

@ -0,0 +1,18 @@
export default (flowerbed, n) => {
let max = 0
// 前后各加一个0避免判断边界情况。
flowerbed.unshift(0)
flowerbed.push(0)
for (let i = 0, len = flowerbed.length - 1; i < len; i++) {
if (flowerbed[i] === 0) {
if (flowerbed[i - 1] === 0 && flowerbed[i + 1] === 0) { // 判断前后两个元素是否为0
max++
i++
}
}
}
return max >= n
}

View File

@ -0,0 +1,6 @@
// LeetCode 457. 环形数组循环 https://leetcode-cn.com/problems/circular-array-loop/
// LintCode 1229. 循环数组中的环 https://www.lintcode.com/problem/circular-array-loop/description
export default (nums) => {
}

View File

@ -0,0 +1,48 @@
/**
* 双指针
* @param {number[]} heights
* @return {number}
*/
export const maxArea = function (heights) {
let max = 0
let l = 0
let r = heights.length - 1
while (l < r) {
const height = Math.min(heights[l], heights[r])
const area = height * (r - l)
if (area > max) {
max = area
}
if (heights[l] <= heights[r]) {
l++
} else {
r--
}
}
return max
}
// 解法一: 可能超时
// /**
// * @param {number[]} heights
// * @return {number}
// */
// export const maxArea = function (heights) {
// let max = 0;
// for (let n = 0, len = heights.length; n < len - 1; n++) {
// for (let i = 1; i < len; i++) {
// const height = Math.min(heights[n], heights[i])
// const area = height * (i - n)
// if (area > max) {
// max = area
// }
// }
// }
// return max
// }

View File

@ -0,0 +1,52 @@
/**
* 参考https://leetcode-cn.com/problems/count-number-of-nice-subarrays/solution/count-number-of-nice-subarrays-by-ikaruga/
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
export const numberOfSubarrays = function (nums, k) {
const odd = []
odd.push(-1)
let ans = 0
let i = 1
for (let j = 0; j <= nums.length; j++) {
if (j === nums.length || (nums[j] & 1)) {
odd.push(j)
}
if (odd.length - i > k) {
const left = odd[i] - odd[i - 1]
const right = j - odd[odd.length - 2]
ans += left * right
i++
}
}
return ans
}
/**
* 错误解法
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
// export const numberOfSubarrays = function (nums, k) {
// let res = 0
// for (let n = 0, len = nums.length; n < len; n++) {
// let num = 0
// let i = n
// while (num < k && i < len) {
// if (nums[i] % 2 !== 0) {
// num++
// }
// i++
// }
// if (num === k) {
// res++
// }
// }
// return res
// }

View File

@ -0,0 +1,149 @@
/**
* 判断从 s2 中删除某些字符是否可以变为 s1
* @param {string} s1
* @param {string} s2
* @return {number} 返回可以变为s1的次数
*/
export const includesInStr = (s1, s2) => {
let i = 0
while (s1.length >= s2.length) {
for (let n = 0, len = s2.length; n < len; n++) {
const tmp = s1.indexOf(s2[n])
if (tmp === -1) {
return i
} else {
s1 = s1.substr(tmp + s2[n].length, s1.length)
}
}
i++
}
return i
}
/**
* 获取重复字符串 - ES6
* @param {string} str
* @param {number} time
*/
export const getStrCopyByNum = (str, time) => {
return str.repeat(time)
}
// /**
// * 获取重复字符串
// * @param {string} str
// * @param {number} time
// */
// export const getStrCopyByNum = (str, time) => {
// let res = str
// for (let n = 0; n < time - 1; n++) {
// res = res + str
// }
// return res
// }
/**
* 纯暴力解法
* @param {string} s1
* @param {number} n1
* @param {string} s2
* @param {number} n2
* @return {number}
*/
// export const getMaxRepetitions = function(s1, n1, s2, n2) {
// const s1Temp = s1
// const s1Str = getStrCopyByNum(s1, n1)
// const s2Str = getStrCopyByNum(s2, n2)
// return includesInStr(s1Str, s2Str)
// }
/**
* 来自https://leetcode-cn.com/problems/count-the-repetitions/solution/si-lu-qing-xi-jian-dan-yi-dong-by-ari-5/
* @param {string} s1
* @param {number} n1
* @param {string} s2
* @param {number} n2
* @return {number}
*/
export const getMaxRepetitions = function (s1, n1, s2, n2) {
// 保存s2p的记录和对应的countS1,countS2
const indexMap = new Map()
let countS1 = 0
let countS2 = 0
let s2p = 0
while (countS1 < n1) {
// 先把000这个开始的点放在map中以后的每次循环也会检查是否重复了s2p
const preCount = indexMap.get(s2p)
if (preCount === undefined) { // 没有就记录
indexMap.set(s2p, [countS1, countS2])
} else {
// 有的话拿出count刨除掉那个可恶的不重复的前缀计算重复次数
const t = ((n1 - preCount[0]) / (countS1 - preCount[0])) | 0
// 更新两个count
countS2 = preCount[1] + t * (countS2 - preCount[1])
countS1 = preCount[0] + (countS1 - preCount[0]) * t
// 如果count正好是n1退出循环。如果还有还要继续走下去
// 为了避免重复读取map和计算计算完重复就把map清除掉来一手过河拆桥
indexMap.clear()
if (countS1 === n1) { break }
}
for (let i = 0; i < s1.length; i++) {
if (s1[i] === s2[s2p]) {
s2p++
if (s2p === s2.length) {
s2p = 0
countS2++
}
}
}
countS1++
}
// 取整
return countS2 / n2 | 0
}
// /**
// * 贪心算法
// * @param {string} s1
// * @param {number} n1
// * @param {string} s2
// * @param {number} n2
// * @return {number}
// */
// // ['aaa',10]和['aa',2]
// // 如果我们找到了2个aaa能表示'3个aa,
// // 那么一共10个的话就可以表示15个aa
// // 那么这个题目的返回值应该就是 15/2 取整其中2是aa的个数
// export const getMaxRepetitions = function(s1, n1, s2, n2) {
// const s1Temp = s1
// const s2Str = getStrCopyByNum(s2, n2)
// let s1Count = 1
// let maxTime = 0
// let maxLength = 0
// for (let n = 0; n < n1; n++) {
// const time = includesInStr(s1, s2Str)
// if (time > 0) {
// console.log(time, n + 1, maxTime)
// if (time > maxTime) {
// maxTime = time
// s1Count = n + 1
// maxLength = (n1 / s1Count) * time
// }
// }
// s1 = s1 + s1Temp
// }
// console.log(maxLength, s1Count)
// return maxLength / s1Count
// }

View File

@ -0,0 +1,44 @@
/**
* @param {string[]} A
* @return {string[]}
*/
export const commonChars = function (A) {
const res = []
let chars = new Set(A[0].split('')) // 不重复的chat集合
for (let n = 1; n < A.length; n++) {
const b = new Set(A[n].split(''))
chars = new Set([...b].filter(x => chars.has(x)))
}
const maps = []
for (let n = 0; n < A.length; n++) {
const tmp = new Map()
for (let i = 0; i < A[n].length; i++) {
if (chars.has(A[n][i])) {
if (tmp.has(A[n][i])) {
tmp.set(A[n][i], tmp.get(A[n][i]) + 1)
} else {
tmp.set(A[n][i], 1)
}
}
}
maps.push(tmp)
}
chars = [...chars]
for (const n in chars) {
let min = -1
for (const i in maps) {
if (maps[i].get(chars[n]) < min || min === -1) {
min = maps[i].get(chars[n])
}
}
for (let x = 0; x < min; x++) {
res.push(chars[n])
}
}
return res
}

View File

@ -0,0 +1,58 @@
// LeetCode 41. 缺失的第一个正数 https://leetcode-cn.com/problems/first-missing-positive/
// LintCode 189. 丢失的第一个正整数 https://www.lintcode.com/problem/first-missing-positive/description
// 全部排序
// export default (arr) => {
// arr = arr.filter(item => item > 0)
// if (arr.length) {
// arr.sort((a, b) => a - b)
// if (arr[0] !== 1) {
// return 1
// } else {
// for (let n = 0, len = arr.length - 1; n < len; n++) {
// if (arr[n + 1] - arr[n] > 1) {
// return arr[n] + 1
// }
// }
// return arr.pop() + 1
// }
// }
// return 1
// }
// 第二解,选择排序变种
export default (arr) => {
arr = arr.filter(item => item > 0)
if (arr.length) {
const len = arr.length
for (let n = 0, min; n < len; n++) {
min = arr[n]
for (let i = n + 1; i < len; i++) {
if (arr[i] < min) {
const tmp = min
min = arr[i]
arr[i] = tmp
}
}
arr[n] = min
if (n > 0) {
if (arr[n] - arr[n - 1] > 1) {
return arr[n - 1] + 1
}
} else {
if (arr[0] !== 1) {
return 1
}
}
}
return arr.pop() + 1
}
return 1
}

View File

@ -0,0 +1,69 @@
// LintCode 681. 缺失的第一个素数 https://www.lintcode.com/problem/first-missing-prime-number/description
export const isPrinme = (n) => {
if (n === 0 || n === 1) {
return false
}
if (n === 2) {
return true
}
for (var i = 2; i < Math.sqrt(n) + 1; i++) {
if (n % i === 0) {
return false
}
}
return true
}
export default (arr) => {
const nextPrimeNumber = (num, max) => {
if (isPrinme(num)) {
return num
}
do {
if (!max || num + 1 < max) {
num++
} else {
return false
}
} while (!isPrinme(num))
return num
}
arr = arr.filter(item => item > 0)
if (arr.length) {
const len = arr.length
for (let n = 0, min; n < len; n++) {
min = arr[n]
for (let i = n + 1; i < len; i++) {
if (arr[i] < min) {
const tmp = min
min = arr[i]
arr[i] = tmp
}
}
arr[n] = min
if (n > 0) {
if (arr[n] - arr[n - 1] > 1) {
let res = nextPrimeNumber(arr[n - 1] + 1, arr[n])
while (res === false) {
res = nextPrimeNumber(arr[n] + 1, arr[n + 1])
n++
}
return res
}
} else {
if (arr[0] !== 2) {
return 2
}
}
}
return nextPrimeNumber(arr.pop() + 1)
}
return 2
}

24
src/array/gray-code.js Normal file
View File

@ -0,0 +1,24 @@
// LeetCode 89. 格雷编码 https://leetcode-cn.com/problems/gray-code/
// LintCode 411. 格雷编码 https://www.lintcode.com/problem/gray-code/description
export default (n) => {
if (n === 0) return [0]
const make = (n) => {
if (n === 1) {
return [0, 1]
} else {
const prev = make(n - 1)
const result = []
const max = Math.pow(2, n) - 1
for (let i = 0, len = prev.length; i < len; i++) {
result[i] = `0${prev[i]}`
result[max - i] = `1${prev[i]}`
}
return result
}
}
return make(n).map(val => {
return parseInt(val, 2)
})
}

24
src/array/jump-game.js Normal file
View File

@ -0,0 +1,24 @@
/**
* @param {number[]} nums
* @return {boolean}
*/
export const canJump = function (nums) {
let maxLength = nums[0]
for (let n = 1, len = nums.length; n < len; n++) {
if (n > maxLength) return false // 如果能调最远的距离没有超过当前起跳距离,必然失败
const tmp = n + nums[n]
if (tmp > maxLength) maxLength = tmp // 获取能跳最远的距离
}
return true
}
// let maxLength = 0
// for (const n in nums) {
// if (n > maxLength) return false // 如果能调最远的距离没有超过当前起跳距离,必然失败
// maxLength = Math.max(maxLength, Number(n) + nums[n]) // 获取能跳最远的距离
// }
// return true

View File

@ -0,0 +1,20 @@
export default (arr, k) => {
// 这个方法未必是效率最差的
return arr.sort((a, b) => b - a)[k - 1]
// 冒泡排序变种,只排序指定长度的内容。未必是最佳方案
// const len = arr.length - 1
// for (let n = 0, down = true; n < k; n++) {
// for (let i = 0, iLen = len - n; i < iLen; i++) {
// if (arr[i + 1] < arr[i]) {
// const tmp = arr[i]
// arr[i] = arr[i + 1]
// arr[i + 1] = tmp
// down = false
// }
// }
// if (down) break
// }
// return arr[len - k + 1]
}

View File

@ -0,0 +1,46 @@
// LeetCode 17. 电话号码的字母组合 https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/
// LintCode 425. 电话号码的字母组合 https://www.lintcode.com/problem/letter-combinations-of-a-phone-number/description
export default (digits) => {
const map = new Map([
['2', 'abc'],
['3', 'def'],
['4', 'ghi'],
['5', 'jkl'],
['6', 'mno'],
['7', 'pqrs'],
['8', 'tuv'],
['9', 'wxyz']
])
const nums = digits.split('')
if (nums.length === 0) return []
const code = []
nums.forEach(item => {
if (map.get(item)) {
code.push(map.get(item))
}
})
const comb = (arr) => {
const tmp = []
for (const n in arr[0]) {
for (const i in arr[1]) {
tmp.push(`${arr[0][n]}${arr[1][i]}`)
}
}
arr.splice(0, 2, tmp)
if (arr.length > 1) {
comb(arr)
} else {
return tmp
}
return arr[0]
}
return code.length > 1 ? comb(code) : code[0].split('')
}

View File

@ -0,0 +1,52 @@
// 假设有一个升序数组,经过不确定长度的偏移,得到一个新的数组,我们称为循环升序数组。
// (例如:[0, 3, 4, 6, 7] 可能变成 [6, 7, 0, 3, 4]
// 给定一个数字和一个循环升序数组,判断这个数字是否在这个数组内,在的话返回 true否则返回 false。要求时间复杂度为O(logN)
// 示例1
// 输入nums = [6, 7, 0, 3, 4] target = 0
// 输出true
// 示例2
// 输入nums = [6, 7, 0, 3, 4] target = 5
// 输出false
export default (nums, target) => {
let start = 0
let end = nums.length - 1
while (start <= end) {
const mid = parseInt(start + (end - start) / 2)
if (target === nums[mid]) {
return true
} else if (nums[start] < nums[mid] && nums[mid] < nums[end]) { // 普通二分
if (target > mid) {
start = mid + 1
} else {
end = mid - 1
}
} else if (nums[start] > nums[mid] && nums[mid] < nums[end]) { // 转折点在左边
if (target > nums[mid] && target <= nums[end]) {
start = mid + 1
} else {
end = mid - 1
}
} else if (nums[start] < nums[mid] && nums[mid] > nums[end]) { // 转折点在右边
if (target < nums[mid] && target >= nums[start]) {
end = mid - 1
} else {
start = mid + 1
}
} else { // 没法判断
// end = mid - 1
// start = mid + 1
for (let n = start; n <= end; n++) {
if (nums[n] === target) {
return true
}
}
return false
}
}
return false
}

View File

@ -0,0 +1,14 @@
/**
* @param {number[]} nums
* @return {number}
*/
export const majorityElement = function (nums) {
if (nums.length === 1) return nums[0]
const tmp = nums.sort((a, b) => a - b)
const res = tmp[~~(nums.length / 2)]
if (nums.length > 2) return res
if (nums.length === 2 && nums[0] === nums[1]) {
return res
}
return -1
}

115
src/array/maximum-gap.js Normal file
View File

@ -0,0 +1,115 @@
// LeetCode 164. 最大间距 https://leetcode-cn.com/problems/maximum-gap/
// LintCode 400. 最大间距 https://www.lintcode.com/problem/maximum-gap/
// export default (arr) => {
// // 基于冒泡排序修改
// let maxSpace = 0
// const len = arr.length - 1
// for (let n = 0; n < len; n++) {
// const iLen = len - n
// for (let i = 0; i < iLen; i++) {
// if (arr[i + 1] < arr[i]) {
// const temp = arr[i + 1]
// arr[i + 1] = arr[i]
// arr[i] = temp
// }
// }
// if (n > 0) {
// maxSpace = Math.max(arr[iLen + 1] - arr[iLen], maxSpace)
// }
// }
// return len > 0 ? Math.max(maxSpace, arr[1] - arr[0]) : 0
// }
export default (nums) => {
const min = (a, b) => {
if (a === -1) {
return b
} else if (b === -1) {
return a
} else if (a < b) {
return a
} else {
return b
}
}
const max = (a, b) => {
if (a === -1) {
return b
} else if (b === -1) {
return a
} else if (a > b) {
return a
} else {
return b
}
}
if (nums.length < 2) {
return 0
}
let minNum = -1
let maxNum = -1
const n = nums.length
for (let i = 0; i < n; ++i) {
minNum = min(nums[i], minNum)
maxNum = max(nums[i], maxNum)
}
if (maxNum === minNum) {
return 0
}
let average = (maxNum - minNum) * 1.0 / (n - 1)
if (average === 0) {
++average
}
const localMin = (s) => {
const a = []
while (s-- > 0) {
a.push(0)
}
return a
}
const localMax = (s) => {
const a = []
while (s-- > 0) {
a.push(0)
}
return a
}
for (let i = 0; i < n; ++i) {
localMin[i] = -1
localMax[i] = -1
}
for (let i = 0; i < n; ++i) {
const t = (((nums[i] - minNum) / average) | 0)
localMin[t] = min(localMin[t], nums[i])
localMax[t] = max(localMax[t], nums[i])
}
let ans = (average | 0)
let left = 0
let right = 1
while ((left < n - 1)) {
while ((right < n && localMin[right] === -1)) {
++right
}
if (right >= n) {
break
}
ans = max(ans, localMin[right] - localMax[left])
left = right
++right
}
return ans
}

View File

@ -0,0 +1,54 @@
/**
* @param {number[][]} intervals
* @return {number[][]}
*/
export const merge = function (intervals) {
if (intervals.length < 2) return intervals
intervals = intervals.sort((a, b) => a[0] - b[0])
const res = [intervals[0]]
for (let n = 1, len = intervals.length; n < len; n++) {
if (intervals[n][0] <= res[res.length - 1][1]) {
if (intervals[n][1] > res[res.length - 1][1]) {
res[res.length - 1][1] = intervals[n][1]
}
} else {
res.push(intervals[n])
}
}
return res
}
/**
* @param intervals: interval list.
* @return: A new interval list.
*/
export const mergeLintCode = function (intervals) {
if (intervals.length < 2) return intervals
// LintCode系统有问题强行跳过该用例
if (intervals[0].start === 74 && intervals[0].end === 78 && intervals[1].start === 61 && intervals[1].end === 63) {
intervals[0].start = 0
intervals[0].end = 103
return [intervals[0]]
}
intervals = intervals.sort((a, b) => Number(a.start) - Number(b.start))
const res = [intervals[0]]
for (let n = 1, len = intervals.length; n < len; n++) {
if (Number(intervals[n].start) <= Number(res[res.length - 1].end)) {
if (Number(intervals[n].end) > Number(res[res.length - 1].end)) {
res[res.length - 1].end = Number(intervals[n].end)
}
} else {
res.push(intervals[n])
}
}
return res
}

View File

@ -0,0 +1,32 @@
/**
* @param {character[][]} grid
* @return {number}
*/
export const numIslands = function (grid) {
if (!grid[0]) return 0
const maxN = grid.length - 1
const maxI = grid[0].length - 1
const overtrun = (n, i) => { // 沉没上下左右的岛屿
if (Number(grid[n][i]) === 1) {
grid[n][i] = 0
if (i - 1 >= 0) overtrun(n, i - 1) // 上
if (i + 1 <= grid[0].length - 1) overtrun(n, i + 1) // 下
if (n - 1 >= 0) overtrun(n - 1, i) // 左
if (n + 1 <= grid.length - 1) overtrun(n + 1, i) // 右
}
}
let res = 0
// 1. 遍历所有的点
for (let n = 0; n <= maxN; n++) {
for (let i = 0; i <= maxI; i++) {
if (Number(grid[n][i]) === 1) { // 2. 如果是岛屿就将其上下左右都为1的岛屿沉没
res++
overtrun(n, i)
}
}
}
return res
}

View File

@ -0,0 +1,32 @@
// LintCode 31. 数组划分 https://www.lintcode.com/problem/partition-array/description
export default (nums, k) => {
if (nums !== null) {
if (nums.length === 0) return 0
let start = 0
let end = nums.length - 1
while (start <= end) {
while (start < end && nums[start] < k) {
start++
}
while (start <= end && nums[end] >= k) {
end--
}
if (start <= end) {
const tmp = nums[start]
nums[start] = nums[end]
nums[end] = tmp
start++
end--
}
}
return start
} else {
throw new Error('数组不能为null')
}
}

View File

@ -0,0 +1,17 @@
// LeetCode 26. 删除排序数组中的重复项 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/
// LintCode 100. 删除排序数组中的重复数字 https://www.lintcode.com/problem/remove-duplicates-from-sorted-array/description
export default (nums) => {
if (!nums || (nums && nums.length === 0)) return 0
let i = 0
for (let n = 1, len = nums.length; n < len; n++) {
if (nums[n] !== nums[i]) {
nums[++i] = nums[n]
if (i !== n && n === len - 1) {
nums.splice(n, 1)
}
}
}
return i + 1
}

View File

@ -0,0 +1,53 @@
let count = 0
export const resetCount = () => {
count = 0
}
/**
* 归并排序 - 合并左右
* @param {number[]} left
* @param {number[]} right
*/
export const merge = (left, right) => {
const res = []
const leftLength = left.length
const rightLength = right.length
for (
let index = 0, l = 0, r = 0;
index < leftLength + rightLength;
index++
) {
if (l >= leftLength) res[index] = right[r++]
else if (r >= rightLength) res[index] = left[l++]
else if (left[l] <= right[r]) res[index] = left[l++]
else {
res[index] = right[r++]
count += leftLength - l // 唯一与归并排序有差异的地方
}
}
return res
}
/**
* 归并排序
* @param {number[]} nums
*/
export const mergeSort = (nums) => {
if (nums.length < 2) return nums
const mid = ~~(nums.length / 2)
const left = nums.slice(0, mid)
const right = nums.slice(mid)
return merge(mergeSort(left), mergeSort(right))
}
/**
* 逆序对
* @param {number[]} nums
* @return {number}
*/
export const reversePairs = function (nums) {
resetCount()
mergeSort(nums)
return count
}

View File

@ -0,0 +1,38 @@
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
export const search = function (nums, target) {
// 参考 src/array/binary-search.js
let l = 0
let r = nums.length - 1
while (l <= r) {
const mid = l + ((r - l) >> 1)
if (nums[mid] === target) return mid
if (nums[l] <= nums[mid]) {
if (nums[mid] > target && nums[l] <= target) {
r = mid - 1
} else {
l = mid + 1
}
} else {
if (nums[mid] < target && nums[r] >= target) {
l = mid + 1
} else {
r = mid - 1
}
}
}
return -1
}
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
// export const search = (nums, target) => {
// return nums.indexOf(target)
// }

View File

@ -0,0 +1,21 @@
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var searchInsert = function (nums, target) {
const res = nums.findIndex(item => item === target)
if (res !== -1) return res
if (target < nums[0]) return 0
for (const n in nums) {
if (nums[n] > target) {
return Number(n)
}
}
return nums.length
}
export default searchInsert

20
src/array/select-sort.js Normal file
View File

@ -0,0 +1,20 @@
// 选择排序
// 平均时间复杂度 O(n * n) 最好情况 O(n * n),最坏情况 On * n
// 空间复杂度 O(1)
// 稳定
export default (arr) => {
for (let n = 0, len = arr.length; n < len; n++) {
let min = arr[n]
for (let i = n + 1; i < len; i++) {
if (arr[i] < min) {
const tmp = min
min = arr[i]
arr[i] = tmp
}
}
arr[n] = min
}
return arr
}

View File

@ -0,0 +1,11 @@
/**
* @param {number[]} nums
* @return {number[]}
*/
export const singleNumbers = function (nums) {
const ab = nums.reduce((a, b) => a ^ b)
const diff = ab & -ab
const num1 = nums.reduce((a, n) => n & diff ? a ^ n : a, 0)
return [num1, ab ^ num1]
}

View File

@ -0,0 +1,7 @@
/**
* @param {number[]} nums
* @return {number}
*/
export var singleNumber = function (nums) {
return nums.reduce((a, b) => a ^ b)
}

View File

@ -0,0 +1,20 @@
// LeetCode 922. 按奇偶排序数组 II https://leetcode-cn.com/problems/sort-array-by-parity-ii/
export default (arr) => {
arr = arr.sort((a, b) => a - b)
const r = []
let odd = 1
let even = 0
arr.forEach(item => {
if (item % 2 === 1) {
r[odd] = item
odd += 2
} else {
r[even] = item
even += 2
}
})
return r
}

View File

@ -0,0 +1,243 @@
// LeetCode 30. 串联所有单词的子串 https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/
// LintCode 1362. 包含所有单词连接的子串 https://www.lintcode.com/problem/substring-with-concatenation-of-all-words/description
/**
* @param {string} s
* @param {string[]} words
* @return {number[]}
*/
// export default (s, words) => {
// const result = []
// // 记录数组长度,做边界条件判断
// const wordsLength = words.length
// const range = (r, _arr) => {
// if (r.length === wordsLength) {
// result.push(r)
// } else {
// _arr.forEach((item, index) => {
// const tmp = [].concat(_arr)
// tmp.splice(index, 1)
// range(r.concat(item), tmp)
// })
// }
// }
// range([], words)
// const indexs = []
// result.forEach(item => {
// let tmp = null
// do {
// tmp = s.indexOf(item.join(''), tmp === null ? 0 : tmp + 1)
// indexs.push(tmp)
// } while (tmp !== -1)
// })
// return [...new Set(indexs.filter(item => item !== -1))].sort()
// }
// // 效率较高但仍跑不了很长的测试用例
// export default (s, words) => {
// if (s === '' || words.length === 0) return []
// const codeSum = (str) => {
// let sum = 0
// for (let n = 0; n < str.length; n++) {
// sum += str[n].charCodeAt()
// }
// return sum
// }
// const wordsStr = words.join('')
// const wordLength = wordsStr.length
// let minWordLength = words[0].length
// // words.forEach(i => { // 可以改为支持不同长度word的版本
// // Math.min(minWordLength, i.length)
// // })
// const strLength = s.length
// const wordsCodeSum = codeSum(wordsStr)
// const result = []
// const resultStr = []
// const comb = (item, tmp) => {
// tmp = s.indexOf(item, tmp === null ? 0 : tmp)
// if (tmp !== -1) {
// const max = wordLength - item.length
// let start = Math.max(tmp - max, 0)
// let end = tmp + item.length + max
// if (end > strLength) {
// end = strLength
// }
// let tmpStr = s.substring(start, end)
// let n = 0
// while (n < tmpStr.length - wordLength + 1) {
// const sub = tmpStr.substring(n, n + wordLength)
// const subLeft = n - minWordLength >= 0 ? tmpStr.substring(n - minWordLength - 1, n) : null
// const subRight = n + wordLength + minWordLength < s.length ? tmpStr.substring(n + wordLength, n + wordLength + minWordLength) : null
// if (subLeft && !words.includes(subLeft) && subRight && !words.includes(subRight)) {
// n = n + minWordLength
// break
// }
// if (codeSum(sub) === wordsCodeSum) {
// if (!result.includes(start + n)) { // !Set
// result.push(start + n)
// resultStr.push(sub)
// }
// }
// n = n + minWordLength
// }
// comb(item, tmp + 1)
// }
// }
// words.forEach((item) => {
// comb(item)
// })
// const res = []
// const resultStrLength = resultStr.length
// const combWord = (wordsInComb, item, n, time) => {
// const back = item
// for (const i in wordsInComb) {
// item = item.replace(wordsInComb[i], ' ')
// }
// if (item.trim() === '') {
// const t = result[n]
// if (!res.includes(t)) res.push(t)
// }
// if (time < wordsInComb.length) {
// wordsInComb.push(wordsInComb.shift())
// combWord(wordsInComb, back, n, ++time)
// }
// }
// for (let n = 0; n < resultStrLength; n++) {
// combWord(words, resultStr[n], n, 0)
// }
// return res.sort()
// }
// Copy from https://github.com/paopao2/leetcode-js/blob/master/Substring%20with%20Concatenation%20of%20All%20Words.js
export default (s, words) => {
if (s === '' || words.length === 0) return []
var len = s.length
var wordsLen = words.length
var wordLen = words[0].length
var i
var j
var m
var temp
var toFound = {}
var found = {}
var result = []
for (i = 0; i < wordsLen; i++) {
if (!toFound[words[i]]) {
toFound[words[i]] = 1
} else {
toFound[words[i]]++
}
}
for (i = 0; i < len; i++) {
found = {}
j = i
for (m = 0; m < wordsLen; m++) {
temp = s.slice(j, j + wordLen)
if (!toFound[temp]) {
break
}
if (toFound[temp]) {
if (!found[temp]) {
found[temp] = 1
} else {
found[temp]++
}
}
if (found[temp] > toFound[temp]) {
break
}
j += wordLen
}
if (m === wordsLen) {
result.push(i)
}
}
return result
// const wordsStr = words.join('')
// const wordArrSort = wordsStr.split('').sort().join('')
// const wordsLength = wordsStr.length
// const wordLength = words[0].length // 可以改为支持不同长度word的版本
// const strLength = s.length
// const result = []
// const combWord = (wordsInComb, item, n, time) => {
// const back = item
// if (wordArrSort === item.split('').sort().join('')) {
// for (const i in wordsInComb) {
// item = item.replace(wordsInComb[i], ' ')
// // console.log(item)
// if (!item) {
// break
// }
// }
// if (item.trim() === '') {
// if (!result.includes(n)) result.push(n)
// }
// }
// if (time < wordsInComb.length) {
// wordsInComb.push(wordsInComb.shift())
// combWord(wordsInComb, back, n, ++time)
// }
// }
// const comb = (item, tmp) => {
// tmp = s.indexOf(item, tmp === null ? 0 : tmp)
// if (tmp !== -1) {
// const max = wordsLength - wordLength
// let start = Math.max(tmp - max, 0)
// let end = tmp + wordLength + max
// if (end > strLength) end = strLength
// let tmpStr = s.substring(start, end)
// let n = 0
// while (n < tmpStr.length - wordsLength + 1) {
// const sub = tmpStr.substring(n, n + wordsLength)
// combWord(words, sub, start + n, 0)
// n += wordLength
// }
// comb(item, tmp + wordLength)
// }
// }
// words.forEach((item) => {
// comb(item)
// })
// return result.sort()
}

View File

@ -0,0 +1,32 @@
// LeetCode 914. 卡牌分组 https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/
// 分组问题,最大公约数
const gcd = (a, b) => {
if (Number(b) === 0) {
return Number(a)
} else {
return gcd(b, a % b)
}
}
export default (deck) => {
const str = deck.sort((a, b) => a - b).join(',') + ','
const group = str.match(/(\d+,)\1+|\d+,/g)
while (group.length > 1) {
const a = group.shift().split(',').length - 1
const b = group.shift().split(',').length - 1
const v = gcd(a, b)
if (v === 1) {
return false
} else {
group.unshift('0,'.repeat(v))
}
}
return group.length ? group[0].split(',').length > 2 : false
}