算法(algorithm),在數學(算學)和計算機科學之中,爲任何良定義的具體計算步驟的一個序列,經常使用於計算、數據處理和自動推理。精確而言,算法是一個表示爲有限長列表的有效方法。算法應包含清晰定義的指令用於計算函數。 - 來自維基百科git
算法看起來在離咱們通常的開發者不是很近,可是實際上又和咱們的開發息息相關。不一樣的算法可能用不一樣的時間、空間或效率來完成一樣的任務。一個算法的優劣能夠用空間複雜度與時間複雜度來衡量。如今想一想大學的時候沒有好好的學習算法和數據結構真的是後悔的吐血。本文只是簡單理解算法,並不會深刻的討論。畢竟每個深刻討論都夠喝一壺了。只是理解一下算法的思惟和實現。 畢竟9月是個跳槽黃金時期,說不定能幫上你得忙呢?github
算法在在我看來最直觀的做用就在於能夠強化咱們的編程思惟邏輯。讓我麼養成是用簡單的方式去解決問題的思惟方式。下面咱們一塊兒來入算法的坑。本文中提到的相關的例子,都是相對比較簡單的。大部分來自leetcode數組部分。代碼都是我本身實現的,並不必定是最優解。歡迎各位大佬在issue中提交
更好的實現方式。解析都寫到了代碼註釋中。算法
爲了不一些沒必要要的錯誤,文中的示例使用Typescript
編寫,JavaScript
部分代碼在這兒,本文主要分了兩大部分 LeetCode/簡單算法編程
給定一個排序數組,你須要在原地刪除重複出現的元素,使得每一個元素只出現一次,返回移除後數組的新長度。不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。數組
示例 給定數組 nums = [1,1,2], 函數應該返回新的長度 2, 而且原數組 nums 的前兩個元素被修改成 1, 2。 你不須要考慮數組中超出新長度後面的元素。緩存
/** * 1 刪除排序數組中的重複項 * 給定一個排序數組,你須要在原地刪除重複出現的元素,使得每一個元素只出現一次,返回移除後數組的新長度。 * 不要使用額外的數組空間,你必須在原地修改輸入數組並在使用 O(1) 額外空間的條件下完成。 * 示例 * 給定數組 nums = [1,1,2], * 函數應該返回新的長度 2, 而且原數組 nums 的前兩個元素被修改成 1, 2。 * 你不須要考慮數組中超出新長度後面的元素。 */
const removeDuplicates = function(nums: number[]): number {
let i: number = 0
for (let j = 0; j < nums.length; j++) {
if(nums[j] !== nums[i]) {
i++
nums[i] = nums[j]
}
}
nums.splice(i+1)
console.log(nums)
console.log(nums.length)
return i + 1
}
/** * 解析 * 方法 雙指針法 * i是慢指針,j是快指針 當咱們遇到 nums[j] \neq nums[i]nums[j]≠nums[i] 時,跳太重複項的運行已經結束, * 所以咱們必須把它(nums[j]nums[j])的值複製到 nums[i + 1]nums[i+1]。而後遞增 ii,接着咱們將再次重複相同的過程,直到 jj 到達數組的末尾爲止。 * 複雜度分析: * 時間複雜度: O(n) 假設數組長度是n 那麼i和j最多就是遍歷n步 * 空間複雜度: O(1) */
removeDuplicates([0,0,1,1,1,2,2,3,3,4])
複製代碼
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。設計一個算法來計算你所能獲取的最大利潤。你能夠儘量地完成更多的交易(屢次買賣一支股票)。數據結構
注意:你不能同時參與多筆交易(你必須在再次購買前出售掉以前的股票)。函數
示例性能
輸入: [7,1,5,3,6,4]學習
輸出: 7
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 3 天(股票價格 = 5)的時候 賣出, 這筆交易所能得到利潤 = 5-1 = 4 。 隨後,在第 4 天(股票價格 = 3)的時候買入,在第 5 天(股票價格 = 6)的時候賣出, 這筆交易所能得到利潤 = 6-3 = 3 。
/** * 2: 買賣股票的最佳時機 * 給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。 * 設計一個算法來計算你所能獲取的最大利潤。你最多能夠完成一次交易 * 注意:你不能同時參與多筆交易(你必須在再次購買前出售掉以前的股票) * * 輸入: [7,1,5,3,6,4] * 輸出: 7 * 解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 3 天(股票價格 = 5)的時候賣出, 這筆交易所能得到利潤 = 5-1 = 4 。 * 隨後,在第 4 天(股票價格 = 3)的時候買入,在第 5 天(股票價格 = 6)的時候賣出, 這筆交易所能得到利潤 = 6-3 = 3 。 */
// 第一種方式
const maxProfit = function (prices: number[]): number {
if(prices.length < 2) return 0
// 定義利潤
let count: number = 0
let PreMin:number =prices[0]
// 獲取最大的單天利潤
for (let i = 0; i < prices.length; i++) {
count = Math.max(count, prices[i] - PreMin)
PreMin = Math.min(PreMin, prices[i])
}
console.log(count)
return count
}
/** * 解析: 貪心算法 */
console.log('=================股票最佳購買時機貪心算法===================');
console.log(maxProfit([7,1,5,3,6,4]));
console.log('====================================');
// 第二種方式 這種方式更加簡單
const maxProfitMore = function (prices: number[]) :number{
if(prices.length < 2) return 0
let ret = 0
for (let i = 0; i < prices.length; i++) {
// 若是次日的價格大於當天的,那麼就計算利潤
if (prices[i+1] > prices[i]) {
ret += prices[i+1] - prices[i]
}
}
return ret
}
/** * 解析: 非貪心算法 * 只要下一天的價錢 大於今天的價錢 那咱們就賣出當前天的 最終的結果就是咱們的利潤總和 */
console.log('==================股票最佳購買時機非貪心算法==================');
console.log(maxProfitMore([7,1,5,8,3,6,4]))
console.log('=============================================');
複製代碼
給定一個數組,將數組中的元素向右移動 k 個位置,其中 k 是非負數。
示例 輸入: [1,2,3,4,5,6,7] 和 k = 3
輸出: [5,6,7,1,2,3,4]
解釋:
向右旋轉 1 步: [7,1,2,3,4,5,6]
向右旋轉 2 步: [6,7,1,2,3,4,5]
向右旋轉 3 步: [5,6,7,1,2,3,4]
要求
要求使用空間複雜度爲 O(1) 的原地算法。
/** * 3: 給定一個數組,將數組中的元素向右移動 k 個位置,其中 k 是非負數。 * 要求O(1)的空間複雜度,對原數組進行操做 */
const rotate = function(nums: number[], k: number) {
// 循環k,經過k咱們能夠肯定須要移動的次數
for (let i = 0; i < k; i++) {
// 先在前面插入咱們須要移動的地方
nums.unshift(nums[nums.length -1 - i])
}
// 最後再去處理咱們的數組
nums.splice(nums.length - k, k)
}
rotate([1,2,3,4,5,6,7],3)
複製代碼
給定一個整數數組,判斷是否存在重複元素。若是任何值在數組中出現至少兩次,函數返回 true。若是數組中每一個元素都不相同,則返回 false。
示例 輸入: [1,2,3,1] 輸出: true
/** * 4: 存在重複 * 給定一個整數數組,判斷是否存在重複元素。 * 若是任何值在數組中出現至少兩次,函數返回 true。若是數組中每一個元素都不相同,則返回 false。 * * 這個必定不是最優解 */
const containsDuplicate = function (nums: number[]) :boolean{
// 設置flag
let judge = false
// 容錯判斷
if (nums.length <= 1) {
return judge
}
// 經過最簡單直白的去重的思想去處理
let current :number[] =[]
for (let i = 0; i < nums.length; i++) {
if (current.indexOf(nums[i]) === -1) {
current.push(nums[i])
} else {
return judge = true
}
}
return judge
}
console.log('================是否存在重複算法====================');
console.log(containsDuplicate([3,1]))
console.log('====================================');
// 這個實際上是很是常見並且簡單得一個算法 可是要考慮到得狀況多一點
複製代碼
給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現兩次。找出那個只出現了一次的元素。
示例
輸入: [2,2,1]
輸出: 1
要求 你的算法應該具備線性時間複雜度。 不適用額外的空間來實現
/** * 5: 只出現一次得數字 * 給定一個非空整數數組,除了某個元素只出現一次之外,其他每一個元素均出現兩次。找出那個只出現了一次的元素。 * 你的算法應該具備線性時間複雜度。 不使用額外空間來實現 */
const singleNumber = function(nums: number[]) :number {
let index= -1
// 雙層進行比對 目的是當前key和數組中的每個key進行比較
nums.forEach((key, j)=> {
//每次循環小遊標
let count = 0
for (let k = 0; k < nums.length; k++) {
if (key === nums[k]) {
count += 1
}
// 循環完找出符合條件的下標
if (k === nums.length -1 && count === 1) {
index = j
}
}
})
return nums[index]
}
console.log('=================查找單獨數算法===================');
console.log(singleNumber([2,2,1,3,3]))
console.log('====================================');
複製代碼
給定兩個數組,編寫一個函數來計算它們的交集。
示例
輸入: nums1 = [1,2,2,1], nums2 = [2,2]
輸出: [2,2]
要求
/** * 6:求兩個數組的交集 */
const intersect = function (nums1:number[], nums2:number[]) :number[]{
let arr:number[] = []
for (let i = 0; i < nums1.length; i++) {
if (nums2.indexOf(nums1[i]) !== -1 ) {
nums2.splice(nums2.indexOf(nums1[i]), 1)
arr.push(nums1[i])
}
}
return arr
}
/** * 解析: 在求交集的過程當中。主要的思想是關於什麼是交集。 * 兩個數組的重合部分理論上來說就是交集 * 循環其中一個數組nums1在後在另一個數組nums2中比對是否出現,若是出現的話就刪除nums2中出現過的數組(注意是修改nums2) */
intersect([1,2,2,1], [2,2])
複製代碼
給定一個由整數組成的非空數組所表示的非負整數,在該數的基礎上加一.你能夠假設除了整數 0 以外,這個整數不會以零開頭。
示例
輸入: [1,2,3]
輸出: [1,2,4]
/** * 7:加1 * 給定一個由整數組成的非空數組所表示的非負整數,在該數的基礎上加一。 * 你能夠假設除了整數 0 以外,這個整數不會以零開頭。 */
const plusOne =function (nums: number[]) :number[] {
let j = nums.length - 1
// js沒法正常表示大於16位的整數【非科學計數】
for (let i = nums.length - 1; i >=0; i--) {
// 開始逐個進行加法運算
if(i == j) {
// 大於10的狀況
if(nums[i] + 1 >= 10){
nums[i] = nums[i] + 1 -10
j--
// 最後一次循環
if (i === 0) {
nums.unshift(1)
}
} else {
nums[j] ++
}
} else {
break
}
}
console.log(nums)
return nums
}
/** * 解析: 若是使用太大的數的話轉成數字再加1是不行的,咱們須要對數組中的的單個數據進行運算,一樣的是以輔助遊標進行運算 * 輔助遊標j的主要做用是記錄須要+1的位置,若是當前的下標不等於j那麼就跳出了循環:同時也提升了性能 */
console.log('================加1算法====================');
console.log(plusOne([8,2,1,,1,2,2,2,3,5,5,5,5,5,2,3,4,2,3,4,5,5,5,5,2,9]))
console.log('====================================');
複製代碼
給定一個數組 nums,編寫一個函數將全部 0 移動到數組的末尾,同時保持非零元素的相對順序。
示例
輸入: [0,1,0,3,12]
輸出: [1,3,12,0,0]
要求
/** * 8: 移動零 * 給定一個數組 nums,編寫一個函數將全部 0 移動到數組的末尾,同時保持非零元素的相對順序。 */
const moveZeroes = function(nums: number[]) {
// 0出現的個數
let j = 0
nums.forEach((el: number, index: number, arr: number[]) => {
if (nums[j] === 0) {
nums.splice(j, 1)
nums.push(0)
} else {
j++
}
})
console.log(nums)
}
/** * 解析: 新建一個小遊標j 這個是用來標識0出現的地方,每次移動完以後小遊標是不變化的,由於原數組已經修改因此要固定一下游標 * 雙遊標法在算法真的很實用 */
console.log('==================移動零算法==================');
moveZeroes([1,2,0,0,0,1])
console.log('====================================');
複製代碼
給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。你能夠假設每一個輸入只對應一種答案,且一樣的元素不能被重複利用。
示例
給定 nums = [2, 7, 11, 15], target = 9
由於 nums[0] + nums[1] = 2 + 7 = 9
因此返回 [0, 1]
/** * 第一種解法 * @param nums * @param target */
const twoSumA = function (nums: number[], target: number) :number[] {
console.log('兩數求和第一種解法')
let arr = [0,0] ,flag = false
for (let i = 0; i < nums.length; i++) {
compare(i)
if (flag) {
arr = [i, compare(i)]
break
}
}
/** * @param num */
function compare(index: number) :number {
for (let j = 0; j < nums.length; j++) {
if (j!== index && nums[index] + nums[j] === target) {
flag = true
return j
}
}
}
return arr
}
/** * 第二種解法 */
const twoSumB = function (nums: number[], target: number) :number[] {
let arr = [0,0]
console.log('兩數求和第二種解法')
for (let i = 0; i < nums.length; i++) {
for (let j = 0; j < nums.length; j++) {
if (j!== i && nums[i] + nums[j] === target) {
return arr = [i,j]
}
}
}
return arr
}
// 在進行一個數組中兩個數得比較中:必定要注意在相加得時候要排除自身去進行相加。
console.log('=================兩數之和算法===================');
console.log(twoSumA([3,2,4],6))
console.log(twoSumB([2, 7, 11, 15],9))
console.log('====================================');
複製代碼
判斷一個 9x9 的數獨是否有效。只須要根據如下規則,驗證已經填入的數字是否有效便可。
示例
給定
[
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
複製代碼
輸出 js true
說明
/** * 10:有效得數獨 */
let board = /* [ ["5","3",".",".","7",".",".",".","."], ["6",".",".","1","9","5",".",".","."], [".","9","8",".",".",".",".","6","."], ["8",".",".",".","6",".",".",".","3"], ["4",".",".","8",".","3",".",".","1"], ["7",".",".",".","2",".",".",".","6"], [".","6",".",".",".",".","2","8","."], [".",".",".","4","1","9",".",".","5"], [".",".",".",".","8",".",".","7","9"] ]*/
[["7",".",".",".","4",".",".",".","."],
[".",".",".","8","6","5",".",".","."],
[".","1",".","2",".",".",".",".","."],
[".",".",".",".",".","9",".",".","."],
[".",".",".",".","5",".","5",".","."],
[".",".",".",".",".",".",".",".","."],
[".",".",".",".",".",".","2",".","."],
[".",".",".",".",".",".",".",".","."],
[".",".",".",".",".",".",".",".","."]
]
const isValidSudoku = function (board: string[][]): boolean {
let isPass = true
const sudokuDeep = 9 // 數獨深度
// 判斷行和列
for (let i = 0; i < sudokuDeep; i++) {
let row:any = {}
let col:any = {}
for (let j = 0; j < sudokuDeep; j++) {
// 判斷行
/** * 判斷方式 * 首先判斷不爲'.' => 而後判斷是否存在row對象中 */
if (board[i][j] !== '.') {
if (row[board[i][j]]) {
console.log(board[i][j])
return isPass = false
} else {
row[board[i][j]] = board[i][j]
}
}
// 判斷列
if (board[j][i] !== '.') {
if (col[board[j][i]]) {
console.log(board[j][i]);
return isPass = false
} else {
col[board[j][i]] = board[j][i]
}
}
// 判斷九宮格 經過餘數的形式判斷出來當前所處的9宮格
// 先計算出位置
let c = Math.floor(i/3) // col位置
let r = Math.floor(j/3) // row 位置
// 勾勒出九宮格
for (let m = c*3; m < c*3 + 3; m++) {
for (let n = r * 3; n < r * 3 + 3; n++) {
if (m === i && n === j) {
// m === i && n === j 這時指向同一個位置
continue
} else {
// 最重要的一次求值判斷
if(board[m][n] != '.' && board[i][j]!== '.' && (board[i][j]) === board[m][n]) {
return isPass = false
}
}
}
}
}
}
return isPass
}
console.log('=================有效數獨算法結果===================');
console.log(isValidSudoku(board))
console.log('====================================');
複製代碼
給定一個 n × n 的二維矩陣表示一個圖像。將圖像順時針旋轉 90 度。
示例
給定
[
[1,2,3],
[4,5,6],
[7,8,9]
],
複製代碼
輸出
[
[7,4,1],
[8,5,2],
[9,6,3]
]
複製代碼
要求
你必須在原地旋轉圖像,這意味着你須要直接修改輸入的二維矩陣。請不要使用另外一個矩陣來旋轉圖像。
/** * 11: 旋轉圖像 **/
const matrix = [
[1,2,3],
[4,5,6],
[7,8,9]
]
//
/* const matrix = [ [ 5, 1, 9,11], [ 2, 4, 8,10], [13, 3, 6, 7], [15,14,12,16] ] */
const rotateMaps = function (matrix:number[][]) {
const n = matrix.length
// 倒敘循環進行90度的反轉
for (let i = n-1; i >= 0; i--) {
// 新數組補位到原數組中,爲了是實現原地的旋轉操做,若是不須要
for (let j = 0; j < n ; j++) {
// console.log(`當前座標[${i},${j}]`)
const current = matrix[i][j]
matrix[j].push(current)
// 沒完成一組的賦值操做,就刪除旋轉前數組
if(j === n - 1) {
matrix[i].splice(0, n)
}
}
}
console.log(matrix)
// return matrix
}
console.log('================旋轉圖像算法====================');
console.log(rotateMaps(matrix));
console.log('====================================');
複製代碼
這一部分先出demo,後面的代碼中的解析註釋會慢慢加上
fid爲0表明一級,fid若是和fid爲0的cid相等的話表明二級 以此類推...
/** * 10: 找父親節點 * fid爲0表明一級,fid若是和fid爲0的cid相等的話表明二級 以此類推... */
const findArr = [
{"fid":0,"cid":3,"flag":"最外層3"},
{"fid":0,"cid":4,"flag":"最外層4"},
{"fid":4,"cid":5,"flag":"最外層-4"},
{"fid":5,"cid":6,"flag":"最外層-4-1"},
{"fid":0,"cid":7,"flag":"最外層7"},
{"fid":7,"cid":8,"flag":"最外層-7"},
{"fid":0,"cid":9,"flag":"最外層9"},
{"fid":9,"cid":10,"flag":"最外層9-1"},
{"fid":9,"cid":11,"flag":"最外層9-2"},
{"fid":11,"cid":12,"flag":"最外層9-2-1"}
]
/** * 第一種方法:雙遞歸方式 * @param arr */
const findfid = function (arr: any[]): any[] {
let newArr:any[] = []
for (let i = 0; i < arr.length; i++) {
let flagId = arr[i].cid // 取出來一個flag 這個是用於和下一個級別匹配的
for (let j = 0; j < arr.length; j++) {
const elJ = arr[j]
if (elJ.fid === flagId) { // fid 和 上級id 匹配
(arr[i].children = []).push(elJ)
}
}
// 只存入第一等級
arr[i].fid === 0 && newArr.push(arr[i])
}
return newArr
}
/** * 第二種方法: 使用對象存儲id 而後和fid進行對比 * @param arr */
const findfidByObj = function (arr: any[]): any[] {
let newArr:any[] = []
let flagObj: any = {}
arr.forEach(v => {
flagObj[v.cid] = v
})
arr.forEach (item => {
// 根據當前遍歷對象的fid,去map對象中找到對應索引的id
const top = flagObj[item.fid]
if (top) {
// 若是找到索引,那麼說明此項不在頂級當中,那麼須要把此項添加到,他對應的父級中
(top.children || (top.children = [])).push(item)
} else {
// 若是沒有在map中找到對應的索引ID,那麼直接把當前的item添加到newData結果集中做爲頂級
newArr.push(item)
}
})
return newArr
}
console.log('====================================');
console.log('找父親節點方式');
console.log(findfid(findArr))
console.log(findfidByObj(findArr))
console.log('====================================');
複製代碼
選擇排序(Selection sort)是一種簡單直觀的排序算法。它的工做原理是每一次從待排序的數據元素中選出最小(或最大)的一個元素,存放在序列的起始位置,直到所有待排序的數據元素排完。 選擇排序是不穩定的排序方法。
/** * 交換參數 * @param {*} arr * @param {*} a * @param {*} b */
const swap = function(arr: number[], a:number, b:number) {
let curr = arr[a]
arr[a] = arr[b]
arr[b] = curr
}
/** * * @param {選擇排序算法} arr */
const sort = function (arr: number[]) {
console.time()
for (let i = 0; i < arr.length; i++) {
//假設遍歷的當前第一個是最小的
let minIndex = i
//第二次遍歷把arr[minIndex]和數組中的其餘的值進行遍歷
for (let j = 0; j < arr.length; j++) {
if(arr[minIndex] > arr[j]){
minIndex = j
}
}
//外層循環作交換
swap(arr,minIndex,i)
}
console.log(arr)
console.timeEnd()
}
sort([3,6,28,123,34])
複製代碼
冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。它重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,若是他們的順序(如從大到小、首字母從A到Z)錯誤就把他們交換過來。走訪元素的工做是重複地進行直到沒有相鄰元素須要交換,也就是說該元素已經排序完成。
/** * @param {*冒泡排序算法} arr */
const bubbleSort = function (arr: number[]){
console.log('冒泡算法開始時間:')
console.time()
for (let i = 0; i < arr.length; i++) {
// 這個循環時獲取到以後的項進行比較
for (let j = i+1; j > 0; j--) {
// 這個核心就是 若是當前項小於前一項那麼當前項向上冒泡
if(arr[i] < arr[j-1]){
// 冒泡交換
swap(arr,j,j-1)
}
}
}
console.timeEnd()
console.log(arr)
}
bubbleSort([3,123,6,28,34])
複製代碼
插入排序是基於比較的排序。所謂的基於比較,就是經過比較數組中的元素,看誰大誰小,根據結果來調整元素的位置。
//插入排序算法
/** * * @param {插入排序} arr */
const insertSort = function (arr: number[]){
console.time()
for (let i = 0; i < arr.length; i++) {
// 在一次循環的時候首先緩存下來當前的值和上一個index 緩存上一個index用來比較
let compareIndex = i -1
let currentValue = arr[i]
// 在當前位置能夠比較而且當前的值小於前一項的值的時候插入緩存的值而後修改index
while (compareIndex >=0 && arr[compareIndex] > currentValue) {
arr[compareIndex + 1] = arr[compareIndex]
compareIndex--
}
arr[compareIndex + 1 ] = currentValue
}
console.timeEnd()
console.log(arr)
}
insertSort([3,2,1])
複製代碼
二分查找也稱爲折半查找。是指在有序的數組裏找出指定的值,返回該值在數組中的索引。
/** * 二分查找算法 * 什麼叫二分查找? 二分查找也稱爲折半查找。是指在有序的數組裏找出指定的值,返回該值在數組中的索引。 * (1)從有序數組的最中間元素開始查找,若是該元素正好是指定查找的值,則查找過程結束。不然進行下一步; * (2)若是指定要查找的元素大於或者小於中間元素,則在數組大於或小於中間元素的那一半區域查找,而後重複第一步的操做; * (3)重複以上過程,直到找到目標元素的索引,查找成功;或者直到子數組爲空,查找失敗。 * 注意: 這個先要把數組排序一下 在有序數組中查找 * 優勢是比較次數少,查找速度快,平均性能好; * 其缺點是要求待查表爲有序表,且插入刪除困難。所以,折半查找方法適用於不常常變更而查找頻繁的有序列表。 */
/** * 非遞歸實現 * @param {*} arr * @param {*} target */
function binarySearcNoRecursive(arr: number[], target: number){
let low: number = 0, high: number = arr.length-1
while(low <= high) {
// 首先找到中間位置
let middle = ((high + low ) / 2)
if( target === arr[middle]){
return middle
} else if (target > arr[middle]){
low = middle + 1
} else if ( target < arr[middle] ){
high = middle -1
}else {
return -1
}
}
}
const result = binarySearcNoRecursive( [1,2,3,4,5,6,7,8,9,10,11,23,44,86], 23)
console.log(`二分查找不用循環找到的位置:${result}`)
/** * 遞歸實現 循環調用自身 * @param {*} arr * @param {*} target */
function binarySearcRecursive(arr: number[], low:number, high: number, target:number){
if(low > high){
return -1
}
let middle = ((high + low ) / 2)
if(arr[middle] === target){
return middle
} else if(arr[middle] > target){
high = middle -1
binarySearcRecursive(arr, low, high, target)
} else if(arr[middle] < target){
low = middle + 1
binarySearcRecursive(arr, low, high, target)
}
}
const recursiveRes = binarySearcNoRecursive( [1,2,3,4,5,6,7,8,9,10,11,23,44,86], 3)
console.log(`二分查找不用循環找到的位置:${recursiveRes}`)
複製代碼
算法再編程中佔據着至關重要的地位,語言的技術均可以速成。可是算法須要紮實的理論知識做爲地基。本文只是根據leetcode中的題目,簡單的實現一下。感覺一下算法的魅力。學習的話我建議仍是系統深刻的學。
相應的JavaScript
示例代碼地址
原文地址 若是以爲有用得話給個⭐吧