题目1: 454.四数相加II
题目&讲解
思路: 注意swift无值取默认值的写法。
本题主要不要纠结组合,顺序是固定的。 最后也只是统计总数。
// @lc code=start
class Solution {
func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int]) -> Int {
var firstMap = [Int: Int]()
var count = 0
for num1 in nums1 {
for num2 in nums2 {
// 注意这种 无值时取默认值的写法
firstMap[num1 + num2] = firstMap[(num1 + num2), default: 0] + 1
}
}
for num3 in nums3 {
for num4 in nums4 {
if let firstGroup = firstMap[0 - num3 - num4] {
count += firstGroup
}
}
}
return count
}
}
// @lc code=end
题目2: 383. 赎金信
题目&讲解
思路: 没有思考数组和map的优劣,这里还是用数组更省时间一些
// @lc code=start
class Solution {
func canConstruct(_ ransomNote: String, _ magazine: String) -> Bool {
var map = [UInt32: Int]()
magazine.unicodeScalars.forEach { map[$0.value] = map[$0.value, default: 0] + 1 }
for item in ransomNote.unicodeScalars {
if let count = map[item.value], count > 0 {
map[item.value]! -= 1
} else {
return false
}
}
return true
}
}
// @lc code=end
题目3: 15. 三数之和
题目&讲解
思路:
补充两点, 在这两个点上卡了一下。
- 在数字A去重的这个点。
之所以可以这样去重, 是因为方案分别用a,b,c 来指代三个元素。
如果a与前一个作为a的 nums[i-1] 值一样, 那么后面的遍历起始条件完全一样, 有结果也必定是重复的。 - 题解中这种去重方式,只能去掉挨着的重复元素。 如果不挨着呢, 比如 1 0 1 2 -3, 是不是会组成两个 [1 2 -3]元组。
思考了下,恍然大悟, 前提是排序了。重复的元素一定是挨着的。
双指针法:
整体思路复述一下
整体建立在排序基础上,所以先排序。
然后定义游标i, 左指针left,右指针right, 分别指代元组中的三个元素a, b, c。
遍历i
计算 i, left, right 下标对应元素之和。
如果过大,right左移。
如果过小,left右移。
直至碰撞。
自己写的时候漏了一层剪枝:if (sorted[i] > 0) { break }。
// @lc code=start
class Solution {
func threeSum(_ nums: [Int]) -> [[Int]] {
let sorted = nums.sorted()
var result = [[Int]]()
for i in 0..<sorted.count {
if (sorted[i] > 0) { break }
if i > 0, sorted[i] == sorted[i - 1] { continue }
var left = i + 1
var right = sorted.count - 1
while left < right {
if sorted[i] + sorted[left] + sorted[right] > 0 { right -= 1 }
else if sorted[i] + sorted[left] + sorted[right] < 0 { left += 1 }
else {
result.append([sorted[i], sorted[left], sorted[right]])
while left < right, sorted[right] == sorted[right - 1] { right -= 1 }
while left < right, sorted[left] == sorted[left + 1] { left -= 1 }
right -= 1
left += 1
}
}
}
return result
}
}
// @lc code=end
题目4:第18题. 四数之和
题目&讲解
思路: 同三数之和
// @lc code=start
class Solution {
func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] {
let sorted = nums.sorted()
var result = [[Int]]()
for i in 0..<sorted.count {
// 一号元素剪枝
if sorted[i] > target, sorted[i] >= 0 { break }
// 一号元素去重
if i > 0, sorted[i] == sorted[i - 1] { continue }
for j in (i + 1)..<sorted.count {
// 二号元素剪枝
if sorted[i] + sorted[j] > target, sorted[i] + sorted[j] >= 0 { break }
// 二号元素去重, 这里注意j > i + 1 确保是本轮的遍历
if j > i + 1, sorted[j] == sorted[j - 1] { continue }
var left = j + 1
var right = sorted.count - 1
while left < right {
if sorted[i] + sorted[j] + sorted[left] + sorted[right] > target { right -= 1 }
else if sorted[i] + sorted[j] + sorted[left] + sorted[right] < target { left += 1 }
else {
print("\([i, j, left, right])")
result.append([sorted[i], sorted[j], sorted[left], sorted[right]])
// 去重
while left < right, sorted[left] == sorted[left + 1] { left += 1 }
while left < right, sorted[right] == sorted[right - 1] { right -= 1 }
right -= 1
left += 1
}
}
}
}
return result
}
}
// @lc code=end