算法(雙指針|動態規划)


雙指針技巧

167 兩數之和

輸入一個升序的有序數組,找到兩數的和等於目標值

const twoSum = (numbers, target) => {
  let start = 0
  let end = numbers.length - 1
  while (start < end) {
    let sum = numbers[start] + numbers[end]
    if (sum == target) {
      return [start + 1, end + 1]
    }
    if (sum > target) {
      end--
      continue
    }
    if (sum < target) {
      start++
      continue
    }
  }
}
console.log(twoSum([1, 2, 3, 4, 5, 6], 11))

125 驗證回文串

只考慮數字和字母

//如果遇到不是數字后者字母直接跳過
const isPalindrome = s => {
  let start = 0,
    end = s.length - 1;
  let reg = /[a-z0-9]/
  while (start < end) {
    const pre = s[start].toLowerCase()
    const suf = s[end].toLowerCase()
    if (!reg.test(pre)) {
      start++
      continue
    }
    if (!reg.test(suf)) {
      end--
      continue
    }
    if (pre !== suf) {
      return false
    }
    start++
    end--
  }
  return true
}
console.log(isPalindrome('abba'))

雙向冒泡排序

const bubbleSort = arr => {
    let isSwap = '',tail=arr.length-1
    for (let i = 0; i < tail; i++) {
        isSwap = false
        for (let j = tail; j > i; j--) {
            if (arr[j] > arr[j + 1]) {
                isSwap = true
                swap(j, j + 1, arr)
            }
        }
        for (let j = i; j < tail; j++) {
            if (arr[j] > arr[j + 1]) {
                isSwap = true
                swap(j, j + 1, arr)
            }
        }
        if (!isSwap) {
            break
        }
    }
    return arr
}
console.log(bubbleSort([1, 10, 3, 4, 5, 6, 1221, 1, 2, 3, 4, 4, 5]))

41 給定一個未排序的整數數組,找出其中沒有出現的最小的正整數

輸入: [1,2,0]
輸出: 3
示例 2:

輸入: [3,4,-1,1]
輸出: 2
示例 3:

輸入: [7,8,9,11,12]
輸出: 1

采用集合

const firstMissing = nums => {
    const set = new Set()
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] >= 0&& nums[i] <= nums.length) {
            set.add(nums[i])
        }
    }
    for (let i = 0; i <= nums.length; i++) {
        if (!set.has(i)) {
            return i
        }
    }
    return nums.length
}

我自己改的

const firstMissing = nums => {
    if (nums == null || nums.length < 1)
        return 1
    let a = nums.filter(v => v > 0).sort((a, b) => a - b)
    let s = 1
    while (s < a.length) {
        if (s < a[s - 1]) {
            return s
        }
        s++
    }
}

如何在 10 億數中找出前 1000 大的數

const firstMissing = nums => {
    let i = 1
    while (1) {
        if (nums[i] > 1000) {
            return nums[i]
        }
        if (!(typeof nums[i] == "number")) {
            return '不好意思沒有找到'
        }
        i++
    }
}

貪心算法

中心思想: 大事化小,小事化了

動態規划

通過把原問題分解為相對簡單的子問題的方式求解復雜問題的方法

總結就是:

  • 有最優解的結構

  • 找到子問題

  • 以"自底向上"的方式計算最優解的值

  • 可以從已計算的信息中構建出最優的路徑

最少硬幣數

確定狀態

最后一步(最優策略種使用的最后一枚硬幣ak)

化成子問題(最少的硬幣拼出最小的面值27-ak)

轉移方程

f[x]=Math.min(f[x-2]+1,f[x-5]+1,f[x-7]+1)

初始化條件和邊界情況

f[0]=0,如果不能評出Y,f[Y]=正無窮

計算順序

從小到大

const coinChange = (A, M) => {
  let n = A.length;
  let f = [];
  f[0]=0
  for (let i = 1; i <= M; i++) {
    //選擇硬幣
    f[i] = Infinity
    for (let j = 0; j < n; j++) {
      //i>=A[j] 你的硬幣不能大於我的目標值,相當於我要拼出10塊錢,你不能為11塊錢
      //i-A[j] 11-1,-3,-5 的值
      if (i >= A[j] && f[i - A[j]] != Infinity && f[i - A[j]] + 1 < f[i]) {
        f[i] = f[i - A[j]] + 1
      }
      console.log(f)
    }
  }
  if (f[M] == Infinity) {
    return -1
  } else {
    return f[M]
  }
}
console.log(coinChange([1,2,5], 15))

114

給定m行n列的網格,有一個機器人從左上角(0,0)出發,每一步可以向下或者向有走一步,

問有多少種不同的方式

確定狀態

  • 左下角左邊設為(m-1,n-1)
  • 那么前一步機器人一定是再(m-2,n-1)或者(m-1,n-2)

子問題

  • 那么機器人有x種方式從左上角走到(m-2,n-1)

  • 有y種方式從左上角走到(m-1,n-2)

  • 則機器人有x+y種方式走到(m-1,n-1)

轉化方程

對於任意一個格子(i,j)

f[i][j]=f[i-1][j]+f[i][j-1]

有多少種方式走到(i,j)=(i-1,j)+(i,j-1)

初始條件和邊界情況

  • 初始條件:f[0][0]=1 因為機器人只有一種方式到左上角
  • 邊界情況: i=0 或 j=0 則前一步只能有一個方向過程f[i][j]=1

計算順序

const Solution = (m, n) => {
  let f = Array.from({length:m},v=>[])
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      //按照行列的情況進行循環
      if (i == 0 || j == 0) {
        f[i][j] = 1;
      } else {
        f[i][j] = f[i - 1][j] + f[i][j - 1]
      }
    }
  }
  return f[m - 1][n - 1]
}
console.log(Solution(3, 3))

116

有n塊石頭分別在x軸的0,1,...n-1位置

一只青蛙在石頭0,想跳到石頭n-1

如果青蛙在第i塊石頭上,他最多可以向右跳距離a[j]

問青蛙能夠跳到石頭n-1

例子
[2,3,1,1,4]
true
[3,2,1,0,1]
false

存在型動態規划


確定狀態

最后一步:如果青蛙能跳到最后一塊石頭n-1,那我們考慮他跳的最后一步

這一步是從石頭i調過來,i<n-1

需要兩個條件同時滿足:

  • 青蛙可以跳到石頭i
  • 最后一步不超過跳躍的最大距離:n-1-i<a[j]

子問題

狀態:設f[j]表示青蛙能不能跳到石頭j

轉移方程

計算順序

const Solution = A => {
  if (A == null || A.length == 0) {
    return false
  }
  let f = [true,]
  for (let i = 1; i < A.length; i++) {
    f[i] = false
    for (let j = 0; j < i; j++) {
      if (f[j] && (j + A[j]) >= i) {
        f[i] = true
        break
      }
    }
  }
  return f[A.length-1]
}
console.log(Solution([2, 3, 1, 1, 4]))
console.log(Solution([3,2,1,0,4]))


###########################...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM