经典冒泡排序
思路:比较相邻的元素,如果第一个比第二个大,就交换他们两个,对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,最后的元素应该会是最大的数,
首次遍历区间:[0, arr.length -2],二次遍历区间:[首次遍历的位置 + 1, arr.length - 1],
function bubbleSort(arr) {
for(let i = 0; i < arr.length - 1; i++){
for(let j = i + 1; j <= arr.length - 1; j++) {
if(arr[i] > arr[j]) {
const tempVal = arr[i]
arr[i] = arr[j]
arr[j] = tempVal
}
}
}
return arr
}
双指针-快速排序
思想:来自于快速排序,在一个有序的数组(从小到大)中最左边一定是最小值,最右边是最大值。我们可将最小值与最大值相加与目标值进行比较,如果两数之和大于目标值,我们就让最大值小一点(读取第二个最大值),如果两数之和小于目标 值,我们就让最小值大一点(读取第二个最小值),如果两数之和刚好等于目标值,保存最大值,最小值,并且让最大值小一 点,最小值大一点。需要注意的是前提条件是数组必须有序!
function sum2(arr,tartgetVal) {
const resulutArr = []
const sortArr = arr.sort(function(a,b){
return a - b
})
let start = 0
let end = sortArr.length - 1
while(start < end) {
if (sortArr[start] + sortArr[end] === tartgetVal) {
resulutArr.push([sortArr[start], sortArr[end]])
start += 1
end -= 1
} else if (sortArr[start] + sortArr[end] >= tartgetVal) {
end -= 1
} else {
start += 1
}
}
return resulutArr
}
const arr = [1, 4, 3, 2, 6, 5]
sum2(arr,6)
/* [Array(2),Array(2)]
[1,5]
[2,4]
*/
function sum3(arr, targetVal) {
const sortArr = arr.sort((a,b) => {
return a - b;
})
console.log(sortArr)
let result = []
const len = sortArr.length - 3
for(let i = 0; i < sortArr.length -3; i++) {
let left = i + 1, right = sortArr.length - 1
while(left < right) {
if(sortArr[i] + sortArr[left] + sortArr[right] === targetVal) {
result.push([sortArr[i], sortArr[left], sortArr[right]])
left += 1
right -= 1
} else if (sortArr[i] + sortArr[left] + sortArr[right] > targetVal) {
right -= 1
} else {
left += 1
}
}
}
console.log(result)
return result
}
const arr = [1, 4, 3, 2, 6, 5, 9, 8, 21, 22, 34, 10, 14]
sum3(arr, 10)
/*
[Array(3), Array(3), Array(3)]
0: [1, 3, 6]
1: [1, 4, 5]
2: [2, 3, 5]
*/
两个超长数字字符串和(直接相加会发生溢出)
思路:将超长字符串转换成数组,然后遍历元素进行计算,这里要特别注意字符串的长度差异,可以借助数组的reverse方法进行右对齐,计算完后再对数组reverse恢复,最后就是再次将结果转换成字符串。
const str1 = '1116781231231231231'
const str2 = '2224561297978978978989089'
function fn(str1,tr2) {
const arr = []
// 右对齐进行计算
const arr1 = str1.split('').reverse()
const arr2 = str2.split('').reverse()
const len = arr1.length >= arr2.length ? arr1.length : arr2.length
// 逢十进一
let flag = 0
for(let i = 0; i < len; i++) {
if (arr1[i] === undefined) {
arr1[i] = '0'
} else if (arr1[i] === undefined) {
arr2[i] = '0'
}
const tempResult = (Number(arr1[i]) + Number(arr2[i]) + flag) % 10
arr.push(tempResult)
flag = Number(arr1[i]) + Number(arr2[i]) + flag >= 10 ? 1 : 0
}
return arr.reverse().join('')
}
console.log(fn(str1,str2))
// 2224562414760210210220320
编辑距离
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
1、插入一个字符
2、删除一个字符
3、替换一个字符
示例1
输入: word1 = “horse”, word2 = “ros”
输出: 3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
function getDistance(str1,str2) {
}
最长公共子序列(可以非连续)
思路:嵌套循环保存所有两个字符串的公共元素和下标,然后进行过滤
过滤条件:
1、不是按下标从小到大排序的项剔除;
2、相邻元素相同下标不同的剔除前一项;
function fn(text1,text2) {
const arr = []
for(let i = 0; len1 = text1.length, i < len1; i++) {
for(let j = 0; len2 = text2.length, j < len2; j++) {
if (text1[i] === text2[j] && arr.findIndex(item => j === item[0]) === -1) {
arr.push([j,text2[j]])
}
}
}
console.log(arr)
/*
0: (2) [0, "o"]
1: (2) [2, "o"]
2: (2) [17, "o"]
3: (2) [6, "a"]
4: (2) [9, "b"]
5: (2) [10, "t"]
6: (2) [11, "y"]
7: (2) [12, "c"]
8: (2) [14, "d"]
9: (2) [16, "e"]
*/
const result = JSON.parse(JSON.stringify(arr))
for(let i = 0; len3 = result.length, i < len3 - 1; i++) {
if (result[i][0] > result[i+1][0] || result[i][1] === result[i+1][1]) {
result.splice(i,1)
}
}
console.log(result)
/*
0: (2) [2, "o"]
1: (2) [6, "a"]
2: (2) [9, "b"]
3: (2) [10, "t"]
4: (2) [11, "y"]
5: (2) [12, "c"]
6: (2) [14, "d"]
7: (2) [16, "e"]
*/
return result.reduce((prev,next) => {
return prev + next[1]
},'')
}
const text1 = 'oajbtycqwmde'
const text2 = 'opoklgauibtycxdueo'
console.log(fn(text1,text2)) //oabtycde
最长连续公共子序列
const text1 = 'oajbtycqwmde'
const text2 = 'opoklgauibtycxdueo'
function fn(text1,text2) {
const arr = []
for(let i = 0; len1 = text1.length, i < len1; i++) {
for(let j = 0; len2 = text2.length, j < len2; j++) {
if (text1[i] === text2[j] && arr.findIndex(item => j === item[0]) === -1) {
arr.push([j,text2[j]])
}
}
}
console.log(arr)
/*
0: (2) [0, "o"]
1: (2) [1, "a"]
2: (2) [3, "b"]
3: (2) [4, "t"]
4: (2) [5, "y"]
5: (2) [6, "c"]
6: (2) [10, "d"]
7: (2) [11, "e"]
*/
const result = JSON.parse(JSON.stringify(arr))
const strArr = []
for(let i = 0; len3 = result.length, i < len3 - 1; i++) {
if (result[i+1][0] - result[i][0] === 1) {
strArr.push(result[i][1])
if (i <= len3 - 3 && result[i+2][0] - result[i+1][0] !== 1) {
strArr.push(result[i+1][1])
}
} else {
strArr.push('-')
}
}
console.log(strArr)
// ["o", "a", "-", "b", "t", "y", "c", "-", "d", "e"]
const tempResult = strArr.join('').split('-').filter(item => !!item) || []
console.log(tempResult)
// ["oa", "btyc", "de"]
let maxLength = tempResult[0].length
let maxStr = tempResult[0] || 'null'
tempResult.forEach(item => {
if (item.length > maxLength) {
maxStr = item
}
})
return maxStr
// btyc
}
console.log(fn(text2,text1)) //btyc
零钱兑换
多段存在交集的时间段,判断是否存在间隔
思路: 先对时间段的开始时间进行升序排列;因为存在时间段的并集,所以需要对排序后的时间段,依次获取连续的时间段的最大时间并集,间断的就从新获取连续(时间段的开始时间小于前一时间段的结束时间)的时间段的最大时间并集,然后得到一系列的最大并集,然后对这一系列的最大并集进行时间间隔的判断。
例:时间段[1,3],[2,7],[8,11],[1,5 ],首先对时间段的开始时间进行升序排列,得到[1,3],[1,5],[2,7],[8,11],然后对这一系列的时间段进行遍历,用数组arr保存初始时间段[1,3],并使用变量temp记录[1,3]做为连续时间段的最大并集,遍历到[1,5]时,[1,5]开始时间小于temp[1,3]的结束时间,说明存在交集需要合并,因为已经是升序排列过所以开始时间不用比较,结束时间取较大,temp[1,3]更新为[1,5],另外需要更新数组arr已保存最大并集的结束时间为5,此时arr为[1,5];当遍历到[2,7],[2,7]开始时间小于temp[1,5]的结束时间,存在交集需要合并,因为升序排列所以开始时间不用比较,结束时间取较大,temp[1,5]更新为[1,7],同时更新数组arr已保存的最大并集的结束时间为7,此时arr为[1,7];当遍历到[8,11]时,[8,11]开始时间大于temp[1,7]的结束时间,不存在交集不需要合并,是一个新的最大并集,更新temp为[8,11],同时数组arr需要保存该最大并集,此时arr为[[1,7],[8,11]];依次遍历得到一系列的最大并集,然后进行间隙判断。
gapCheck(timeRangeList) {
const __timeRangeList = JSON.parse(JSON.stringify(timeRangeList))
// 按开始时间排序, 会改变原数据
__timeRangeList.sort((a, b) =>
a.from <= b.from ? -1 : 1
)
const timeRangeListLength = __timeRangeList.length
const timeRangeFirst = __timeRangeList[0]
if (timeRangeListLength > 1) {
let from = timeRangeFirst.from
let to = timeRangeFirst.to
const tempArr = []
tempArr.push({ from, to})
for (let i = 1; i < timeRangeListLength; i++) {
const item = __timeRangeList[i]
// from小于等于前一项的to, 需要合并,获取较大值的to
if (item.from <= to && item.to > to) {
to = item.to
// 更新tempArr的最后一项的结束值
tempArr[tempArr.length - 1].to = to
}
// from大于前一项的to,再次保存
if (item.from > to) {
from = item.from
to = item.to
tempArr.push({from,to})
}
}
// console.log('tempArr', tempArr)
for (let i = 0; i < tempArr.length - 1; i++) {
// 前一项的截止时间
const prevto = tempArr[i].to
// 后一项的开始时间月份
const nextfrom = tempArr[i * 1 + 1 + ''].from
// 间隔1个月及以上需要提示
const diffTime =
new Date(nextfrom).getTime() -
new Date(prevto).getTime()
const oneMounth = 1 * 30 * 24 * 60 * 60 * 1000
if (diffTime > oneMounth) {
this.$notify.error({
message:'There is a gap found in between your time range'})
return false
}
return true
}
}
}