十一、算法-排序和搜索
1、排序和搜索简介
/**
* 一、排序和搜索是什么?
* - 排序:把某个乱序的数组变成升序或者降序的数组
* - 搜索:找出数组中某个元素的下标
* 二、js中的排序和搜索
* - js中的排序:数组的sort方法
* - js中的搜索:数组的indexOf方法
* 三、排序算法
* - 冒泡排序
* - 选择排序
* - 插入排序
* - 归并排序
* - 快速排序
* - ...
* 四、搜索算法
* - 顺序搜索
* - 二分搜索
* - ...
*/
2、javascript实现:冒泡排序
Array.prototype.bubbleSort = function () {
for (let i = 0; i < this.length - 1; i++) {
for (let j = 0; j < this.length - 1 - i; j++) {
if (this[j] > this[j + 1]) {
const temp = this[j]
this[j] = this[j + 1]
this[j + 1] = temp
}
}
}
}
3、javascript实现:选择排序
Array.prototype.selectionSort = function () {
for (let i = 0; i < this.length - 1; i++) {
let indexMin = i
for (let j = i; j < this.length; j++) {
if (this[j] < this[indexMin]) {
indexMin = j
}
}
if (indexMin !== i) {
const temp = this[i]
this[i] = this[indexMin]
this[indexMin] = temp
}
}
}
4、javascript实现:插入排序
Array.prototype.insertionSort = function () {
for (let i = 0; i < this.length; i++) {
const temp = this[i]
let j = i
while (j > 0) {
if (this[j - 1] > temp) {
this[j] = this[j - 1]
} else {
break
}
j -= 1
}
this[j] = temp
}
}
5、javascript实现:归并排序
Array.prototype.mergeSort = function () {
const rec = (arr) => {
if (arr.length === 1) {
return arr
}
const mid = Math.floor(arr.length / 2)
const left = arr.slice(0, mid)
const right = arr.slice(mid, arr.length)
const orderLeft = rec(left)
const orderRight = rec(right)
const res = []
while (orderLeft.length || orderRight.length) {
if (orderLeft.length && orderRight.length) {
res.push(orderLeft[0] < orderRight[0] ? orderLeft.shift() : orderRight.shift())
} else if (orderLeft.length) {
res.push(orderLeft.shift())
} else if (orderRight.length) {
res.push(orderRight.shift())
}
}
return res
}
const res = rec(this)
res.forEach((n, i) => {
this[i] = n
})
}
6、javascript实现:快速排序
Array.prototype.quickSort = function () {
const rec = (arr) => {
if (arr.length <= 1) {
return arr
}
const left = []
const right = []
const mid = arr[0]
for (let i = 1; i < arr.length; i++) {
if (arr[i] < mid) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return [...rec(left), mid, ...rec(right)]
}
const res = rec(this)
res.forEach((n, i) => {
this[i] = n
})
}
7、javascript实现:顺序搜索
Array.prototype.sequentialSearch = function (item) {
for (let i = 0; i < this.length; i++) {
if (this[i] === item) {
return i
}
}
return -1
}
8、javascript实现:二分搜索
Array.prototype.binarySearch = function (item) {
let low = 0
let high = this.length - 1
while (low <= high) {
const mid = Math.floor((low + high) / 2)
const element = this[mid]
if (element < item) {
low = mid + 1
} else if (element > item) {
high = mid - 1
} else {
return mid
}
}
return -1
}
9、力扣解题(21. 合并两个有序链表)
var mergeTwoLists = function (list1, list2) {
const res = new ListNode(0)
let p = res
let p1 = list1
let p2 = list2
while (p1 && p2) {
if (p1.val < p2.val) {
p.next = p1
p1 = p1.next
} else {
p.next = p2
p2 = p2.next
}
p = p.next
}
if (p1) {
p.next = p1
}
if (p2) {
p.next = p2
}
return res.next
};
10、力扣解题(374. 猜数字大小)
var guessNumber = function (n) {
let low = 1
let high = n
while (low <= high) {
const mid = Math.floor((low + high) / 2)
const res = guess(mid)
if (res === 0) {
return mid
} else if (res === 1) {
low = mid + 1
} else {
high = mid - 1
}
}
};
十二、算法设计思想-分而治之
1、分而治之简介
/**
* 一、分而治之是什么?
* - 分而治之是算法设计中的一种方法
* - 它将一个问题分成多个和原问题相似的小问题,递归解决小问题,再将结果合并以解决原来的问题
* 二、场景一:归并排序
* - 分:把数组从中间一分为二
* - 解:递归地对两个子数组进行归并排序
* - 合:合并有序子数组
* 三、场景二:快速排序
* - 分:选基准,按基准把数组分成两个子数组
* - 解:递归地对两个子数组进行快速排序
* - 合:对两个子数组进行合并
*/
2、力扣解题(226. 翻转二叉树)
var invertTree = function (root) {
if (!root) {
return null
}
return {
val: root.val,
left: invertTree(root.right),
right: invertTree(root.left)
}
};
3、力扣解题(100. 相同的树)
var isSameTree = function (p, q) {
if (!p && !q) return true
if (
p && q && p.val === q.val &&
isSameTree(p.left, q.left) &&
isSameTree(p.right, q.right)
) {
return true
}
return false
};
4、力扣解题(101. 对称二叉树)
var isSymmetric = function (root) {
if (!root) return true
const isMirror = (l, r) => {
if (!l && !r) return true
if (
l && r && l.val === r.val &&
isMirror(l.left, r.right) &&
isMirror(l.right, r.left)
) {
return true
}
return false
}
return isMirror(root.left, root.right)
};
十三、算法设计思想-动态规划
1、动态规划简介
/**
* 一、动态规划是什么?
* - 动态规划是算法设计中的一种方法
* - 它将一个问题分解为相互重叠的子问题,通过反复求解子问题,来解决原来的问题
* 二、动态规划的步骤
* - 定义子问题
* - 反复执行
*/
2、力扣解题(70. 爬楼梯)
var climbStairs = function (n) {
if (n < 2) {
return 1
}
let dp0 = 1
let dp1 = 1
for (let i = 2; i <= n; i++) {
const temp = dp0
dp0 = dp1
dp1 = dp1 + temp
}
return dp1
};
3、力扣解题(198. 打家劫舍)
var rob = function (nums) {
if (nums.length === 0) {
return 0
}
let dp0 = 0
let dp1 = nums[0]
for (let i = 2; i <= nums.length; i++) {
const dp2 = Math.max(dp0 + nums[i - 1], dp1)
dp0 = dp1
dp1 = dp2
}
return dp1
};
十四、算法设计思想-贪心算法
1、贪心算法简介
/**
* 一、贪心算法是什么?
* - 贪心算法是算法设计中的一种方法
* - 期盼通过每个阶段的局部最优选择,从而达到全局的最优
* - 结果不一定是最优
*/
2、力扣解题(455. 分发饼干)
var findContentChildren = function (g, s) {
const sortFunc = function (a, b) {
return a - b
}
g.sort(sortFunc)
s.sort(sortFunc)
let i = 0
s.forEach(n => {
if (n >= g[i]) {
i += 1
}
})
return i
};
3、力扣解题(122. 买卖股票的最佳时机 II)
var maxProfit = function (prices) {
let profit = 0
for (let i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1]
}
}
return profit
};
十五、算法设计思想-回溯算法
1、回溯算法简介
/**
* 一、回溯算法是什么?
* - 回溯算法是算法设计中的一种方法
* - 回溯算法是一种渐进式寻找并构建问题解决方式的策略
* - 回溯算法会先从一个可能的动作开始解决问题,如果不行,就回溯并选择另一个动作,直到将问题解决
* 二、什么问题适合用回溯算法解决?
* - 有很多路
* - 这些路里,有死路,也有出路
* - 通常需要递归来模拟所有的路
*/
2、力扣解题(46. 全排列)
var permute = function (nums) {
const res = []
const backtrack = (path) => {
if (path.length === nums.length) {
res.push(path)
return
}
nums.forEach(n => {
if (path.includes(n)) {
return
}
backtrack(path.concat(n))
})
}
backtrack([])
return res
};
3、力扣解题(78. 子集)
var subsets = function (nums) {
const res = []
const backtrack = (path, l, start) => {
if (path.length === l) {
res.push(path)
return
}
for (let i = start; i < nums.length; i++) {
backtrack(path.concat(nums[i]), l, i + 1)
}
}
for (let i = 0; i <= nums.length; i++) {
backtrack([], i, 0)
}
return res
};