算法与数据结构——第一节

时间复杂度

  • 算法的时间复杂度是一个函数,它定性的描述了该算法的运行时间。常用O()表示(最坏情况复杂度),另外还有"Ω"(最好情况复杂度)、“θ” (平均时间复杂度),
  • 在函数表达式中,只看高阶项,不看低阶项,也不看高阶项的系数

常规的位运算

  • ^(异或):位与位比较,相同为0,不同为1,例如:10010 ^ 10101 = 00111
  1. 一个数异或自身结果0,一个数异或0结果为自身
  2. 异或操作满足交换律和结合律
  • ~(非):按位取反
  • &(且):位与位比较,相同为1,不同为0
  • |(或):位与位比较,有一个为1则结果为1
  • >>(右移):数字右移,右移一位相当于除以二,例如:1010 >> 1 => 0101
  • <<(左移):数字左移,左移一位相当于乘以二,例如:1010 << 1 => 10100

排序算法

1. 选择排序、冒泡排序详解

  • 时间复杂度O(N^2),额外空间复杂度O(1)
  • 选择排序:
<script>
 	function selectSort(arr) {
 		if (arr.length < 2) return
 		for (let i = 0; i < arr.length - 1; i++) {
 			let minIndex = i
			for (let j = i + 1; j < arr.length - 1; j++) {
				minIndex = arr[minIndex] > arr[j] ? j : minIndex
			}
			swap(arr, minIndex, i)
		}
	}
</script>

在这里插入图片描述

  • 冒泡排序:
<script>
	function bubbleSort(arr) {
		if (arr == [] || arr.length < 2) return
		for (let i = arr.length; i > 0; i--) {
			for (let j = 0; j < i; j++) {
				if(arr[j] > arr[j+1])swap(arr, j, j+1)
			}
		}
	}
</script>

在这里插入图片描述

  • 交换数组中两个数的位置
// 常规方式,需要额外一个变量
function swap(arr, index1, index2) {
	let tmp = arr[index1]
	arr[index1] = arr[index2]
	arr[index2] = tmp
}
// 采用异或的方式
function swap(arr, index1, index2) {
	arr[index1] = arr[index1] ^ arr[index2]
	arr[index2] = arr[index1] ^ arr[index2]
	arr[index1] = arr[index1] ^ arr[index2]
}

2. 插入排序详解

  • 时间复杂度O(N^2),额外空间复杂度O(1)
  • 插入排序
function insertSort(arr) {
	if (arr == [] || arr.length < 2) return
	for (let i = arr.length - 1; i >= 0; i--) {
		for (let j = i-1; j >= 0 && arr[j] < arr[j-1]; j++) {
			swap(arr, j, j-1)
		}
	}
}

在这里插入图片描述

3. 归并排序详解

function process(arr, left, right){
	if(left == right)return 
	let mid = Math.floor((left + right) / 2)
	process(arr, left, mid)
	process(arr, mid + 1,  right)
	merge(arr, left, mid, right)
}
function merge(arr, left, mid, right){
	let help = []
	let i = 0, p1 = left, p2 = mid + 1
	while(p1 <= mid && p2 <= right){
		help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]
	}
	while(p1 <= mid){
		help[i++] = arr[p1++]
	}
	while(p2 <= right){
		help[i++] = arr[p2++]
	}
	for(i = 0; i < help.length; i++){
		arr[left+i] = help[i]
	}
}
  • 归并排序时间复杂度可以采用递归master公式求得,T(N) = a * T(N/b) + O(N^d)
  • 可以得出其中a = 2, b = 2, d = 1,log(a, b) = d,满足第二个条件,所以时间复杂度为O(NlogN)
    利用归并排序可以延伸出小和问题,在一个数组中每一个元素的左边比他小的数之和称为小和
let arr = [1, 3, 4, 2, 5]
let min = 0
process(arr, 0, arr.length - 1)
function process(arr, left, right){
	if(left == right)return 
	let mid = Math.floor((left + right) / 2)
	process(arr, left, mid)
	process(arr, mid + 1,  right)
	merge(arr, left, mid, right)
}
function merge(arr, left, mid, right){
	let help = []
	let i = 0, p1 = left, p2 = mid + 1
	while(p1 <= mid && p2 <= right){
		if(arr[p1] <= arr[p2])min += arr[p1] * (right-p2+1)
		help[i++] = arr[p1] <= arr[p2] ? arr[p1++]: arr[p2++]
	}
	while(p1 <= mid){
		help[i++] = arr[p1++]
	}
	while(p2 <= right){
		help[i++] = arr[p2++]
	}
	for(i = 0; i < help.length; i++){
		arr[left+i] = help[i]
	}
}
console.log('小和为:',min)

在这里插入图片描述

其他算法

1. 二分查找

function process(arr, num){
	let left = 0, right = arr.length - 1
	let mid = Math.round((left + right) / 2)
	while(arr[mid] != num){
		if(arr[mid] > num)right = mid - 1
		else if(arr[mid] < num)left = mid + 1 
		mid = Math.round((left + right) / 2)
	}
	if(left > right)console.log('未找到')
	console.log('num位于', mid)
}

在这里插入图片描述

2. 二分递归求范围最大值

function getMax(arr, left, right){
	if(left == right - 1 || left == right)return Math.max(arr[left], arr[right])
	let mid = (left + right) / 2
	let leftMax = getMax(arr, left, mid)
	let rightMax = getMax(arr, mid + 1, right)
	return Math.max(leftMax, rightMax)
}

对于递归算法来说,时间复杂度可以采用master公式计算
公式:T(N) = a * T(N/b) + O(N^d)

  1. log(b,a) > d ===> 复杂度为O(N^log(b,a))
  2. log(b,a) = d ===> 复杂度为O(N^d * logN)
  3. log(b,a) < d ===> 复杂度为O(N^d)
    其中a表示调用子递归的次数,T(N/b)表示子问题的规模,O(N^d)表示除递归外其他操作的时间复杂度
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值