日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

js实用算法

發布時間:2023/12/13 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 js实用算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

判斷文本是否為回文

定義:如果將一個文本翻轉過來,能和原文本完全相等,那么就可以稱之為“回文”。

方法一(字符串、數組內置方法)

123456789101112131415/** 判斷文字是否為回文* @param {string|number} val 需要判斷的文字* @return {boolean} bool 是否為回文 */function isPalindrome1(val){// 允許輸入字符串和數字和布爾值if (typeof val !== 'string') val = val.toString();let newVal = val.split('').reverse().join(''); return val === newVal;}isPalindrome1(121) // trueisPalindrome1('yuzuy') // true

// PS:方法簡單,但效率不高,會產生一個新的變量

方法二(循環)

1234567891011121314151617181920/** 判斷文字是否為回文* @param {string|number} val 需要判斷的文字* @return {boolean} bool 是否為回文 */function isPalindrome2(val){val = val + ''; // 非字符串轉化為字符串 // 這里為什么 i <= j 呢?如果中間只有一個字符,是不需要比較的,它肯定等于它本身!!!for(let i = 0, j = val.length - 1; i < j; i++, j--){if(val.charAt(i) !== val.charAt(j)){return false;}} return true;}isPalindrome2(121) // trueisPalindrome2('yuzuy') // true

PS:網上還有其他解法,大多為以上兩種的變形。

反轉字符串

方法一(字符串、數組內置方法))

借用反轉字符串的方法

12345678910/** 反轉字符串* @param {string} val 需要反轉的字符串* @return {string} str 反轉后的字符串*/function reverseVal1(val){if (typeof val !== 'string') return; return val.split('').reverse().join('');}

方法二(循環)

循環系列

1234567891011121314151617181920212223242526272829303132333435/** 反轉字符串* @param {string} val 需要反轉的字符串* @return {string} str 反轉后的字符串*/function reverseVal2(val){if (typeof val !== 'string') return; let str = '',i = 0,len = val.length;while(i < len){str += val.charAt(len - 1 - i);i++; } return str;}/** 反轉字符串* @param {string} val 需要反轉的字符串* @return {string} str 反轉后的字符串*/function reverseVal3(val){if (typeof val !== 'string') return; let str = '',len = val.length;for(let i = len - 1; i >= 0; i--){str += val.charAt(i)} return str;}

測試:reverseVal(‘abc’) // ‘cba’

階乘

方法一(遞歸)

123456789101112/** 階乘* @param {number} n 需要求的階乘* @return {number} 階乘值*/function factorialize1(n){if(typeof n !== 'number') throw new Error('參數必須為整整')if(n === 1) return 1;// 建議不要使用 arguments.callee,目前已經廢棄了。return n * factorialize1(n - 1);}

PS:上面代碼是一個階乘函數,計算n的階乘,最多需要保存n個調用記錄,復雜度 O(n) 。
遞歸非常耗費內存,因為需要同時保存成千上百個調用幀,很容易發生“棧溢出”錯誤(stack overflow)。

方法二(ES6尾調用優化)

(遞歸優化版)

123456789101112/** 階乘* @param {number} n 需要求的階乘* @return {number} 階乘值*/function factorialize2(n, total = 1){if(typeof n !== 'number' || typeof total !== 'number') throw new Error('參數必須為整整')if(n === 1) return total;return factorialize2(n - 1, n * total)// f(3) => f(2, 3 * 2) => f(1, 6) => 6}

PS:ES6尾調用優化但對于尾遞歸來說,由于只存在一個調用幀,所以永遠不會發生“棧溢出”錯誤。
尾調用(Tail Call)是函數式編程的一個重要概念,本身非常簡單,一句話就能說清楚,就是指某個函數的最后一步是調用另一個函數。

方法三(循環)

1234567891011121314151617/** 階乘* @param {number} n 需要求的階乘* @return {number} 階乘值*/function factorialize3(n){if(typeof n !== 'number') throw new Error('參數必須為整整')if(n === 1) return 1; let total = 1;while(n>1){total = n * total;n--;}return total;}

測試:factorialize1(3) // 6

隨機生成長度為n字符串

方法一

123456789101112131415161718/** 生成指定長度的隨機字符串* @param {number} n 生成字符串個數* @return {string} str 反轉后的字符串*/function randomString1(n){let str = 'abcdefghijklmnopqrstuvwxyz0123456789';let tem = '',i = 0; // Math.random 函數產生值的范圍[0,1)while(i<n){tem += str.charAt(Math.floor(Math.random() * str.length))i++;} return tem;}

PS:Math.round(Math.random()?(str.length - 1))
Math.ceil(Math.random()?(str.length - 1))
Math.floor(Math.random() * str.length)
這三種方式等價,都能生成[0, str.length-1]隨機數

方法二(進制轉化)

12345678/** 生成指定長度的隨機字符串* @param {number} n 生成字符串個數* @return {string} 反轉后的字符串*/function randomString2(n){return Math.random().toString(36).substr(2).slice(0, n)}

PS:該方法原理為隨機產生的數轉換為指定進制字符串
toString(n),n為[2,36],n<=10時只產生0-9也就是10進制數字
該方法有個缺點,產生字符串的長度有一定的限制。

方法三(隨機碼點)

1234567891011121314151617181920/** 生成指定長度的隨機字符串* @param {number} n 生成字符串個數* @return {string} str 反轉后的字符串*/function randomString3(n){let str = ''; function randomChar(){let l = Math.floor(Math.random() * 62);if(l < 10) return l; // 數字部分 0-9if(l < 36) return String.fromCharCode(l + 55); // 大寫字母 return String.fromCharCode(l + 61); // 小寫字母} while(str.length < n) str += randomChar(); return str;}

PS:可以參考對于的ASCII碼表。
測試:randomString1(3) // ‘1sd’

數組去重

方法一(ES6的Set數據結構)

12345678/** 數組去重* @param {array} ary 需要去重的數組* @return {array} 去重后的數組*/function unique1(ary){return [...new Set(ary)];}

方法二(對象的key唯一性)

123456789101112131415161718/** 數組去重* @param {array} ary 需要去重的數組* @return {array} 去重后的數組*/function unique2(ary){let obj = {},i = 0,len = ary.length; while(i < len){if(!obj[ary[i]]){obj[ary[i]] = true; // 如果不存在}i++;}return Object.keys(obj);}

PS:該方法存在一定問題,數組的元素全部被轉化為字符串,因為ES6之前對象的key只能是字符串。
會把數字1和字符串’1’,會被視為同一個值。

方法三(臨時數組判斷插入)

123456789101112131415161718/** 數組去重* @param {array} ary 需要去重的數組* @return {array} 去重后的數組*/function unique3(ary){let tem = [],i = 0,len = ary.length; while(i < len){// tem.indexOf() === -1 同理!tem.includes(ary[i]) ? tem.push(ary[i]) : '';i++;} return tem;}

方法四(判斷首次出現的位置)

如果當前數組的第i項在當前數組中第一次出現的位置不是i,那么表示第i項是重復的,忽略掉。否則存入結果數組。

12345678910111213141516/** 數組去重* @param {array} ary 需要去重的數組* @return {array} 去重后的數組*/function unique4(ary){let tem = [ary[0]],len = ary.length; for(let i = 1; i < len; i++ ){// 核心,首次的索引出現是否為當前的索引if(ary.indexOf(ary[i]) === i) tem.push(ary[i]);} return tem;}

方法五(排序后逐個比較插入)

給傳入數組排序,排序后相同值相鄰,然后遍歷時新數組只加入不與前一值重復的值。

123456789101112131415/** 數組去重* @param {array} array 需要去重的數組* @return {array} 去重后的數組*/function unique5(array){let ary = array.slice();ary.sort();let tem = [ary[0]];for(let i = 0, len = ary.length; i < len; i++){ary[i] !== tem[tem.length - 1] ? tem.push(ary[i]) : '';} return tem;}

PS:返回的數組順序發生了改變。

方法六()

獲取沒有重復的最右一值放入新數組(檢測到有重復值時終止當前循環同時進入頂層循環的下一輪判斷)。

12345678910111213141516/** 數組去重* @param {array} ary 需要去重的數組* @return {array} 去重后的數組*/function unique6(ary){let tem = [];for(let i = 0, len = ary.length; i < len; i++){for(let j = i + 1; j < len; j++){if(ary[i] === ary[j]) j = ++i;}tem.push(ary[i])} return tem;}

測試:unique1([1, 2, 3, 2]) // [1, 2, 3]

出現次數最多的字符

方法一(對象key的唯一性進行累加)

123456789101112131415161718192021222324function maxNum1(str){if(typeof(str) !== 'string') str = str.toString();let obj = {},maxChar = []; // 使用數組保存出現最多次的某些字符str.split('').forEach( (val) => {if(!obj[val]){let demo = obj[val] = 1;}else{obj[val]++;}})let maxCount = Math.max.apply(null, Object.values(obj))// forEach方法總是返回 undefined 且 沒有辦法中止或者跳出 forEach 循環。Object.entries(obj).forEach( item => {if(item[1] == maxCount){maxChar.push(item[0])}})return maxChar;}

測試:maxNum1(‘11223333’) // ‘3’

數組扁平化

實現方法:Array.prototype.flatten(depth),參數depth表示需要扁平化的層數,返回一個新的數組。

方法一(遞歸遍歷數組拼接)

123456789101112131415161718function flatten1(ary){let tem = [],i = 0,len = ary.length;while(i < len){if(Array.isArray(ary[i])){// 遞歸進行上面步驟// [].concat(...ary),它的參數可以為數組或值,作用為將數組或值連接成新數組。tem = tem.concat(flatten1(ary[i]))}else{tem.push(ary[i]);}i++;}return tem;}

PS:可以處理多層數組。

方法二(reduce結合concat)

1234567function flatten2(ary){return ary.reduce((pre, cur) => {return pre.concat(Array.isArray(cur) ? flatten2(cur) : cur)}, []) }

PS:可以處理多層數組。

方法三(轉化為字符串)

12345function flatten2(ary){return ary.toString().split(',')}

PS:返回的數組項將為字符串。

方法四(解構數組)

12345678910111213function flatten4(ary){let tem = []ary.forEach(item => {if(Array.isArray(item)){tem = tem.concat(...item);}else{tem = tem.concat(item);}})return tem;}

PS:只能處理2維數組。
測試:getMaxProfit1([1, 2, 3, [4, 5, 6]]) // [1, 2, 3, 4, 5, 6]

數組中最大差值

方法一

123function getMaxProfit1(ary){return Math.max.apply(null, ary) - Math.min.apply(null, ary);}

測試:getMaxProfit1([1, 2, 3, 4]) // 3

斐波那契數列

這里我們只實現通項公式

方法一

1234567function fib1(n){if(n === 1 || n === 2){return 1;}return fib1(n - 1) + fib1(n - 2);}

PS:時間復雜度為O(2^n),空間復雜度為O(n)

方法二

12345678910111213function fib2(n){let tem = [1, 1];if(n === 1 || n === 2){return 1;}// 數組索引從0開始,數列索引從1開始for(let i = 2; i < n; i++){tem[i] = tem[i-1] + tem[i-2];}return tem[n-1];}

PS:時間復雜度為O(n),空間復雜度為O(n)

方法三

123456789101112function fib2(n){let prev = 1, next = 1,res;for(let i = 2; i < n; i++){res = prev + next; prev = next; next = res;} return res;}

PS:時間復雜度為O(n),空間復雜度為O(1)
測試:fib2(3) // 2

判斷是否為質數(prime number)素數

質數:只能被1和自己整除且大于1的數。
合數:數大于1且因數多余2個(大于1的數質數的補集)。

123456789101112function isPrimeNumber1(n){if(n < 2) return false;if(n === 2) return true; // 最小的質數for(let i = 2; i < n; i++){if(n % i === 0){return false;}}return true;}

測試:isPrimeNumber1(2) // true

最小公約數

12345678910111213141516171819202122232425262728function greatestCommonDivisor1(a, b){if(a < 0 || b < 0) throw new Error('參數只能為正整數');if(a < 2 || b < 2) return 1;let min = a,max = b,arymin = [];if(a > b) {min = b;max = a;}for(let i = 1; i <= min; i++){if(min % i === 0){arymin.push(i);console.log(1)}}arymin.reverse();for(let j = 0, len = arymin.length; j < len; j++){if(max % arymin[j] === 0){return arymin[j];}}}

測試:greatestCommonDivisor1(5, 10) // 5

金額轉大寫

12345678910111213141516function money2Chinese(num) {if(typeof num) throw new Error('參數為數字')let strOutput = ""let strUnit = '仟佰拾億仟佰拾萬仟佰拾元角分'num += "00"const intPos = num.indexOf('.')if (intPos >= 0) {num = num.substring(0, intPos) + num.substr(intPos + 1, 2)}strUnit = strUnit.substr(strUnit.length - num.length)for (let i = 0; i < num.length; i++) {strOutput += '零壹貳叁肆伍陸柒捌玖'.substr(num.substr(i, 1), 1) + strUnit.substr(i, 1)} return strOutput.replace(/零角零分$/, '整').replace(/零[仟佰拾]/g, '零').replace(/零{2,}/g, '零').replace(/零([億|萬])/g, '$1').replace(/零+元/, '元').replace(/億零{0,3}萬/, '億').replace(/^元/, "零元");}

測試:money2Chinese(1234) // 壹仟貳佰叁拾肆元整

總結

以上是生活随笔為你收集整理的js实用算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。