1. 程式人生 > >自行整理面試知識(JS篇)(四)[演算法篇2]

自行整理面試知識(JS篇)(四)[演算法篇2]

陣列插值

大致就是如果一個值在兩個值中間,則他跟這兩個值的差值要不然是異號的,要不然就是為0的,用這種方式可以無視排序的逆序或者正序,注意剪枝、

	let a = [1,2,4,5,6,9,10,13];
	const insertNum = (array,num) => {
		//剪枝
		let idx = insertNumIndexOf(array,num,array[array.length-1] >= array[0]);
		if(idx === array.length){
			array.push(num);
			return;
		}
		if(idx === 0){
			array.unshift(num);
			return;
		}
		if(idx){
			array.splice(idx+1,0,num);
			return;
		}
	}
	const insertNumIndexOf = (array,num,flag) => {
		//雙指標
		//剪枝
		if(flag && array[array.length-1] <= num)return array.length-1;
		if(!flag && array[0] <= num)return 0;
		if(flag && array[0] >= num)return 0
		if(!flag && array[array.length-1] >= num)return array.length-1;
		let pre = 0,next = 0;
		for (let i of array){
			++next;
			let signPre = Math.sign(array[pre]-num);
			let signNext = Math.sign(array[next]-num);
			if(signPre != signNext || signPre === 0)return pre;
			pre++;
		}
	}
	insertNum(a,14);
	console.log(a);

科學計數法

	let a = 1111123445411515;
	const changeNum = (num) => {
		let str = String(a);
		let modNum = str.length%3;
		let ansNum = Math.floor(str.length/3);
		let newstr = new Array();
		for(let i = ansNum ; i > 0 ; i--){
			let idx = i * 3 + modNum;
			newstr[i] = str.slice(idx-3,idx);
		}
		if(modNum == 0)newstr.shift();
		else newstr[0] = str.slice(0,modNum);
		return newstr.join(",");
	}
	console.log(changeNum(a));

正則表示式的方法

	let a = 1111123445411515;
	const changeNum = (num) => {
		let reg = /\B(?=((\d{3})+)$)/g;
		return String(a).replace(reg,',');
	}
	console.log(changeNum(a));

匹配非單詞邊界(位置)且後面跟著三個數字的(三個數字可以零次或多次),且進行正向預查,即必須滿足前面的且後面不參與最後匹配的字元內容。

複雜陣列降維(就是深複製的閹割版)

	let a = [2,3,4,[1,2,[1,3],[1,2]]];
	let newa = [];
	const deepCopy = (array)=>{
		for(let i of array){
			let checkType = typeof(i);
			if(checkType != "object")newa.push(i);
			else{
				deepCopy(i);
			}
		}
	}
	deepCopy(a);
	console.log(newa);

正序列最晚出現位置(二分查詢)

	//二分查詢
	let a = [1,1,1,1,1,1,2,5,6,7,8,9,10,11,12,12,13,14,14,14,14,14];
	const findLastIndexOf = (array,num)=>{
		let mid = Math.floor(a.length / 2);
		let pos = -1;
		let left = 0;
		let right = array.length - 1;
		if(num < a[0])return -1;
		if(num > a[right])return -1;
		if(num === a[right])return right;
		while(Math.abs(left-right) != 1){
			if(array[mid] === num){
				pos = mid;
				left = mid;
				mid = Math.floor((left+right)/2);
			}else if(array[mid] > num){
				right = mid;
				mid = Math.floor((left+right)/2);
			}else{
				left = mid;
				mid = Math.floor((left+right)/2);
			}
		}
		return pos;
	}
	console.log(findLastIndexOf(a,1));

注意剪枝,很重要

多個有序陣列的合併

	//有序合併
	let a = [1,2,3,4,5,9,18,33,666,788,999];
	let b = [2,7,17,32,667,699,1111,2222];
	let c = [0,1,2,3,4,6,7,9];
	const mergeArrayAll = (...argument)=>{
		return argument.reduce((newArray = [],item)=>{
			return mergeArray(newArray,item);
		})
	}
	const mergeArray = (arrayOne,arrayTwo) =>{
		let newArray = [];
		let pre = 0,next = 0;
		while(pre <= arrayOne.length-1 && next <= arrayTwo.length-1){
			let minNum;
			if(arrayOne[pre] < arrayTwo[next]){
				minNum = arrayOne[pre];
				pre++;
			}else{
				minNum = arrayTwo[next];
				next++;
			}
			newArray.push(minNum);
		}
		newArray = newArray.concat(arrayOne.slice(pre));
		newArray = newArray.concat(arrayTwo.slice(next));
		return newArray;
	}
	console.log(mergeArrayAll(a,b,c));

其思想大概就是兩個陣列對比,把最小的那個加入新陣列。把最後得到的陣列返回給高階函式繼續迭代出新的陣列

自然序列取值亂序查值問題

從1 - N的自然序列中隨機取出一個值,再打亂其順序,問如何最快發現那個值的位置

一般是相加,相乘,點陣圖(雜湊)。 巧妙的是異或( 我來給你們做證明: 設 123…^N(去掉了那個值的)為T 設去掉的值為n 則123…n…N為T^n 由於對任何數,都有N^N = 0 N^0 = N; 則有TnT為n^0 (自反律) 即為n 懂怎麼做了嗎??? 硬撕的是二分查詢(先排序,再比較下標的位移)

如果是多個值被移除,我推薦你使用點陣圖(即mark陣列啦)

大數加法/減法

	//大數加法,減法
	let a = 15161161111111;
	let b = 9515616161111;
	const bigNumAdd = (numOne, numTwo) => {
		let strOne = numOne + "";
		let strTwo = numTwo + "";
		let result = [];
		result = [...(strOne.length > strTwo.length ? strOne : strTwo)];
		let maxLength = result.length;
		let newNumArray = new Array(Math.abs(strOne.length - strTwo.length)).fill(0);
		if (strOne.length > strTwo.length) newNumArray = newNumArray.concat([...strTwo]);
		else newNumArray = newNumArray.concat([...strOne]);

		console.log(newNumArray, result);
		for (let i = maxLength - 1; i >= 0; i--) {
			let ans = Number(result[i]) + Number(newNumArray[i]);
			if (ans >= 10) {
				ans = ans % 10;
				result[i] = ans;
				if (i != 0) {
					result[i - 1] = Number(result[i - 1]) + 1;
				} else {
					result.unshift(1);
				}
			} else {
				result[i] = ans;
			}
		}
		return result.join('');
	}
	const bigNumSub = (numOne, numTwo) => {
		let strOne = String(numOne);
		let strTwo = String(numTwo);
		let checkFlag = true;
		if (strOne.length > strTwo.length) checkFlag = true;
		else if (strOne.length < strTwo.length) checkFlag = false;
		else {
			if (strOne > strTwo) checkFlag = true;
			else checkFlag = false;
		}
		let result = [...(checkFlag ? strOne : strTwo)];
		let newNumArray = new Array(Math.abs(strOne.length - strTwo.length)).fill(0)
			.concat([...(checkFlag ? strTwo : strOne)]);
		let maxLength = checkFlag ? strOne.length : strTwo.length;
		for (let i = maxLength - 1; i >= 0; i--) {
			let ans = Number(result[i]) - Number(newNumArray[i]);
			if (ans < 0) {
				ans = ans + 10;
				result[i] = ans;
				result[i - 1] = Number(result[i - 1]) - 1;
				if (result[i - 1] === 0 && i - 1 === 0) result.shift();
			} else {
				result[i] = ans;
			}
		}
		if (!checkFlag) result.unshift("-");
		return result.join("");
	}
	console.log(bigNumAdd(a, b));
	console.log(bigNumSub(a, b));

乘法可以用拆開相乘相加的演算法做,也可以用每一位累加直到最後做進位的方法做,當然演算法大佬可以用很多奇怪的超強演算法搞定。。我等大概是。。難的。。