力扣高效演算法入門
- 1. 兩數之和
- 167. 兩數之和 II - 輸入有序陣列
- 15. 三數之和
- 18. 四數之和
- 509. 斐波那契數
- 70. 爬樓梯
- 53. 最大子陣列和
- 416. 分割等和子集
- 322. 零錢兌換
- 20. 有效的括號
1. 兩數之和
給定一個整數陣列 nums
和一個整數目標值 target
,請你在該陣列中找出 和為目標值 target
的那 兩個 整數,並返回它們的陣列下標。
你可以假設每種輸入只會對應一個答案。但是,陣列中同一個元素在答案裡不能重複出現。
你可以按任意順序返回答案。
示例 1:
輸入:nums = [2,7,11,15], target = 9
輸出:[0,1]
解釋:因為 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
輸入:nums = [3,2,4], target = 6
輸出:[1,2]
示例 3:
輸入:nums = [3,3], target = 6
輸出:[0,1]
提示:
2 <= nums.length <= 10<sup>4</sup>
-10<sup>9</sup> <= nums[i] <= 10<sup>9</sup>
-10<sup>9</sup> <= target <= 10<sup>9</sup>
- 只會存在一個有效答案
進階:你可以想出一個時間複雜度小於 O(n<sup>2</sup>)
的演算法嗎?
Solution
func twoSum(nums []int, target int) []int { for i,x := range nums { for j := i + 1; j < len(nums); j++ { if x+nums[j] == target { return []int{i,j} } } } return nil }
167. 兩數之和 II - 輸入有序陣列
給定一個已按照**非遞減順序排列 ** 的整數陣列 numbers
,請你從陣列中找出兩個數滿足相加之和等於目標數 target
。
函式應該以長度為 2
的整數陣列的形式返回這兩個數的下標值_。_numbers
的下標 從 1 開始計數 ,所以答案陣列應當滿足 1 <= answer[0] < answer[1] <= numbers.length
。
你可以假設每個輸入 只對應唯一的答案 ,而且你 不可以 重複使用相同的元素。
示例 1:
輸入:numbers = [2,7,11,15], target = 9
輸出:[1,2]
解釋:2 與 7 之和等於目標數 9 。因此 index1 = 1, index2 = 2 。
示例 2:
輸入:numbers = [2,3,4], target = 6
輸出:[1,3]
示例 3:
輸入:numbers = [-1,0], target = -1
輸出:[1,2]
提示:
2 <= numbers.length <= 3 * 10<sup>4</sup>
-1000 <= numbers[i] <= 1000
numbers
按 非遞減順序 排列-1000 <= target <= 1000
- 僅存在一個有效答案
Solution
#雙指標
func twoSum(numbers []int, target int) []int {
left,right := 0, len(numbers) - 1
for left < right {
sum := numbers[left] + numbers [right]
if sum == target {
return []int{left + 1, right + 1}
} else if sum < target {
left++
} else {
right--
}
}
return []int{-1,-1}
}
15. 三數之和
給你一個包含 n
個整數的陣列 nums
,判斷 nums
中是否存在三個元素 _a,b,c ,_使得 a + b + c = 0 ?請你找出所有和為 0
且不重複的三元組。
注意:答案中不可以包含重複的三元組。
示例 1:
輸入:nums = [-1,0,1,2,-1,-4]
輸出:[[-1,-1,2],[-1,0,1]]
示例 2:
輸入:nums = []
輸出:[]
示例 3:
輸入:nums = [0]
輸出:[]
提示:
0 <= nums.length <= 3000
-10<sup>5</sup> <= nums[i] <= 10<sup>5</sup>
Solution
#三指標
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;
// 先排序
int n = nums.size();
sort(nums.begin(), nums.end());
// 定義首指標==target
for (int i = 0; i < n; i++) {
if ( i > 0 && nums[i] == nums[i-1])
continue;
int k = n - 1; // 內層首指標
int target = -nums[i];
for (int j = i + 1; j < n; j++) // 內層尾指標
{
if( j > i + 1 && nums[j] == nums[j-1])
continue;
while (j < k && nums[j] + nums[k] > target) { // 遍歷尾指標,找合適序列
--k;
}
// 當前i不滿足
if(j == k) {
break;
}
// 得到符合條件序列
if(nums[j] + nums[k] == target) {
ans.push_back({nums[i],nums[j],nums[k]});
}
}
}
return ans;
}
};
18. 四數之和
給你一個由 n
個整陣列成的陣列 nums
,和一個目標值 target
。請你找出並返回滿足下述全部條件且不重複的四元組 [nums[a], nums[b], nums[c], nums[d]]
(若兩個四元組元素一一對應,則認為兩個四元組重複):
0 <= a, b, c, d < n
a
、b
、c
和d
互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意順序 返回答案 。
示例 1:
輸入:nums = [1,0,-1,0,-2,2], target = 0
輸出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:
輸入:nums = [2,2,2,2,2], target = 8
輸出:[[2,2,2,2]]
提示:
1 <= nums.length <= 200
-10<sup>9</sup> <= nums[i] <= 10<sup>9</sup>
-10<sup>9</sup> <= target <= 10<sup>9</sup>
Solution
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> ans;
int n = nums.size();
if(n < 4)
return ans;
sort(nums.begin(), nums.end());
for (int i = 0; i < n - 3; i++) {
if (i > 0 && nums[i] == nums[i-1])
continue;
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if ((long) nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) {
continue;
}
for (int j = i + 1; j < n - 2; j++) {
if (j > i + 1 && nums[j] == nums[j-1])
continue;
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if ((long) nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) {
continue;
}
// 最內層首尾指標
int m = n - 1, k = j + 1;
while(k < m) {
int sum = nums[i] + nums[j] + nums[k] + nums[m];
if (sum == target) {
ans.push_back({nums[i], nums[j], nums[k], nums[m]});
while (k < m && nums[k] == nums[k + 1]) {
k++;
}
k++;
while (k < m && nums[m] == nums[m - 1]) {
m--;
}
m--;
} else if (sum < target) {
k++;
} else {
m--;
}
}
}
}
return ans;
}
};
509. 斐波那契數
斐波那契數,通常用 F(n)
表示,形成的序列稱為 斐波那契數列 。該數列由 0
和 1
開始,後面的每一項數字都是前面兩項數字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
給你 n
,請計算 F(n)
。
示例 1:
輸入:2
輸出:1
解釋:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:
輸入:3
輸出:2
解釋:F(3) = F(2) + F(1) = 1 + 1 = 2
示例 3:
輸入:4
輸出:3
解釋:F(4) = F(3) + F(2) = 2 + 1 = 3
提示:
0 <= n <= 30
Solution
func fib(n int) int {
if n == 0 {
return 0
} else if n == 1 {
return 1
} else {
return fib(n-2) + fib(n-1)
}
}
70. 爬樓梯
假設你正在爬樓梯。需要 n 階你才能到達樓頂。
每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
注意:給定 n 是一個正整數。
示例 1:
輸入: 2
輸出: 2
解釋: 有兩種方法可以爬到樓頂。
1\. 1 階 + 1 階
2\. 2 階
示例 2:
輸入: 3
輸出: 3
解釋: 有三種方法可以爬到樓頂。
1\. 1 階 + 1 階 + 1 階
2\. 1 階 + 2 階
3\. 2 階 + 1 階
Solution
func climbStairs(n int) int {
if n <= 2 {
return n
}
pre1,pre2 := 2,1
for i := 2; i < n; i++ {
cur := pre1 + pre2
pre2 = pre1
pre1 = cur
}
return pre1
}
53. 最大子陣列和
給你一個整數陣列 nums
,請你找出一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。
子陣列 是陣列中的一個連續部分。
示例 1:
輸入:nums = [-2,1,-3,4,-1,2,1,-5,4]
輸出:6
解釋:連續子陣列 [4,-1,2,1] 的和最大,為 6 。
示例 2:
輸入:nums = [1]
輸出:1
示例 3:
輸入:nums = [5,4,-1,7,8]
輸出:23
提示:
1 <= nums.length <= 10<sup>5</sup>
-10<sup>4</sup> <= nums[i] <= 10<sup>4</sup>
進階:如果你已經實現複雜度為 O(n)
的解法,嘗試使用更為精妙的 分治法 求解。
Solution
#動態規劃
func maxSubArray(nums []int) int {
sum := nums[0]
for i := 1; i < len(nums); i++ {
if nums[i] + nums[i-1] > nums[i] {
nums[i] += nums[i-1]
}
if nums[i] > sum {
sum = nums[i]
}
}
return sum
}
416. 分割等和子集
給你一個 只包含正整數 的 非空 陣列 nums
。請你判斷是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。
示例 1:
輸入:nums = [1,5,11,5]
輸出:true
解釋:陣列可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
輸入:nums = [1,2,3,5]
輸出:false
解釋:陣列不能分割成兩個元素和相等的子集。
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 100
Solution
#動態規劃 #揹包問題 #difficult
func canPartition(nums []int) bool {
n := len(nums)
if n < 2 {
return false
}
sum, maxNum := 0,0
for _,num := range nums {
sum += num
if num > maxNum {
maxNum = num
}
}
// 判斷總和是不是奇數
if sum%2 != 0 {
return false
}
target := sum / 2
if target < maxNum {
return false
}
dp := make([]bool, target+1)
dp[0] = true
for i := 0; i < n; i++ {
v := nums[i]
for j := target; j >= v; j-- {
dp[j] = dp[j] || dp[j-v]
}
}
return dp[target]
}
322. 零錢兌換
給你一個整數陣列 coins
,表示不同面額的硬幣;以及一個整數 amount
,表示總金額。
計算並返回可以湊成總金額所需的 最少的硬幣個數 。如果沒有任何一種硬幣組合能組成總金額,返回 -1
。
你可以認為每種硬幣的數量是無限的。
示例 1:
輸入:coins = [1, 2, 5], amount = 11
輸出:3
解釋:11 = 5 + 5 + 1
示例 2:
輸入:coins = [2], amount = 3
輸出:-1
示例 3:
輸入:coins = [1], amount = 0
輸出:0
示例 4:
輸入:coins = [1], amount = 1
輸出:1
示例 5:
輸入:coins = [1], amount = 2
輸出:2
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 2<sup>31</sup> - 1
0 <= amount <= 10<sup>4</sup>
Solution
#動態規劃
func coinChange(coins []int, amount int) int {
dp := make([]int, amount + 1)
dp[0] = 0
// 初始化為math.MaxInt32
for j := 1; j <= amount; j++ {
dp[j] = math.MaxInt32
}
for i := 0; i < len(coins); i++ {
for j := coins[i]; j <= amount ; j++ {
if dp[j-coins[i]] != math.MaxInt32 {
dp[j] = min(dp[j], dp[j-coins[i]]+1)
}
}
}
// 沒找到能裝滿揹包的, 就返回-1
if dp[amount] == math.MaxInt32 {
return -1
}
return dp[amount]
}
func min(a, b int) int {
if a < b{
return a
}
return b
}
20. 有效的括號
給定一個只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字串 s
,判斷字串是否有效。
有效字串需滿足:
- 左括號必須用相同型別的右括號閉合。
- 左括號必須以正確的順序閉合。
示例 1:
輸入:s = "()"
輸出:true
示例 2:
輸入:s = "()[]{}"
輸出:true
示例 3:
輸入:s = "(]"
輸出:false
示例 4:
輸入:s = "([)]"
輸出:false
示例 5:
輸入:s = "{[]}"
輸出:true
提示:
1 <= s.length <= 10<sup>4</sup>
s
僅由括號'()[]{}'
組成
Solution
#棧
func isValid(s string) bool {
n := len(s)
if n % 2 == 1 {
return false
}
pairs := map[byte]byte {
')':'(',
']':'[',
'}':'{',
}
stack := []byte{}
for i := 0; i < n; i++ {
if pairs[s[i]] > 0 {
if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] {
return false
}
stack = stack[:len(stack)-1]
} else {
stack = append(stack,s[i])
}
}
return len(stack) == 0
}
本文來自部落格園,作者:StimuMing,轉載請註明原文連結:https://www.cnblogs.com/fole-del/p/15815077.html