- 数组(11道):
- 剑指Offer(3):数组中重复的数字
- 剑指Offer(4):二维数组中的查找
- 剑指Offer(11):旋转数组的最小数字
- 剑指Offer(21):调整数组顺序使奇数位于偶数前面
- 剑指Offer(39):数组中出现次数超过一半的数字
- 剑指Offer(42):连续子数组的最大和
- 剑指Offer(45):把数组排成最小的数
- 剑指Offer(51):数组中的逆序对
- 剑指Offer(56):数字在排序数组中出现的次数
- 剑指Offer(56):数组中只出现一次的数字
- 剑指Offer(66):构建乘积数组
面试题3:数组中重复的数字
题目一:
思路一:
时间复杂度:O(nlogn)
空间复杂度:O(n)
代码
func findRepeatNumber(_ nums: [Int]) -> Int {
let newNums = nums.sorted()
for (i, v) in newNums.enumerated() {
if v == newNums[i + 1] {
return v
}
}
return 0
}
思路二:哈希表
时间复杂度:O(n)
空间复杂度:O(n)
代码
func findRepeatNumber(_ nums: [Int]) -> Int {
var map = [Int: Int]()
for item in nums{
if map.keys.contains(item){
map.updateValue(map[item]! + 1, forKey: item)
}else{
map.updateValue(1, forKey: item)
}
}
var num: Int = 0
for (key, value) in map{
if value > 1{
num = key
}
}
return num
}
思路三:原地交换
时间复杂度:O(n)
空间复杂度:O(1)
代码
func findRepeatNumber(_ nums: [Int]) -> Int {
guard nums.count > 0 else {
return -1
}
var nums = nums
for i in 0..<nums.count {
while i != nums[i] {
if nums[i] == nums[nums[i]] {
return nums[i]
}
nums.swapAt(i, nums[i])
}
}
return -1
}
题目二:
思路一:辅助数组
时间复杂度:O(n)
空间复杂度:O(n)
代码
func findRepeatNumber(_ nums: [Int]) -> Int {
var arr = Array.init(repeating: -1, count: nums.count)
for item in nums {
if arr[item] != -1 {
return item
} else {
arr[item] = item
}
}
return -1
}
思路二:类似二分查找
时间复杂度:O(nlogn)
空间复杂度:O(1)
代码
func duplicate(_ nums: [Int]) -> Int? {
// 所有数字都在1到 nums.count-1 大小范围内, min 和 max 表示这个范围
var start = 1
var end = nums.count - 1
while start <= end {
let middle = (end - start) / 2 + min
let countAtRange = nums.filter { $0 >= start && $0 <= middle }.count
//退出条件
if start == end {
if countAtRange > 1 {
return start
} else {
break
}
}
//范围缩小
if countAtRange > (middle - start + 1) {
end = middle
} else {
start = middle + 1
}
}
return -1
}
面试题4:二维数组中的查找
题目一:
思路一
代码
func findNumberIn2DArray(_ matrix: [[Int]], _ target: Int) -> Bool {
if matrix.count == 0 {
return false
}
let rows = matrix.count
let columns = matrix.first!.count
var row = 0
var column = columns - 1
while row < rows && column >= 0 {
let number = matrix[row][column]
if number == target {
return true
} else if target > number {
row = row + 1
} else if target < number {
column = column - 1
}
}
return false
}
面试题11:旋转数组的最小数字
题目一:
思路一
思路二
代码
func minArray(_ numbers: [Int]) -> Int {
var min = 0
var max = numbers.count - 1
while min < max {
let mid = (max + min) / 2
if numbers[mid] > numbers[max] {
min = mid + 1;
}else if numbers[mid] < numbers[max] {
max = mid;
} else {
max -= 1
}
}
return numbers[min]
}
面试题21:调整数组顺序使奇数位于偶数前面
题目一:
思路一
思路二
代码
func exchange(_ nums: [Int]) -> [Int] {
if nums.count == 0 { return [] }
var nums = nums
var l = 0
var r = nums.count - 1
while l < r {
while l < r && nums[l] % 2 != 0 {
l += 1
}
while l < r && nums[r] % 2 == 0 {
r -= 1
}
if l < r {
let temp = nums[r]
nums[r] = nums[l]
nums[l] = temp
}
}
return nums
}
面试题39:数组中出现次数超过一半的数字
题目一:
思路一
思路二:投票法
时间复杂度:O(n)
空间复杂度:O(1)
代码
func majorityElement(_ nums: [Int]) -> Int {
var count = 0
var candidate = nums[0]
for num in nums {
if count == 0 {
candidate = num
}
count += (num==candidate) ? 1:-1
}
return candidate
}
思路三:排序
- 多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。也就是说 多数元素至少占总数组的一半以上,那么在排序好的数组中,多数元素肯定在数组中间也有出现
代码
func majorityElement(_ nums: [Int]) -> Int {
return nums.sorted()[nums.count / 2]
}
思路四:哈希表
- 使用哈希表存储元素出现的次数, 因为多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。所以在进行统计时,可以优化操作
代码
func majorityElement(_ nums: [Int]) -> Int {
//! 初始化操作
var hashMap = [Int:Int]()
for num in nums {
if hashMap[num] == nil {
//! 说明从未保存过,
hashMap[num] = 1
} else {
//! 否则,代表之前已经保存过了,如果是多数元素,那么在+1前,本身出现的次数已经 = nums.count/2
if hashMap[num]! == nums.count/2 {
return num
} else {
hashMap[num] = hashMap[num]!+1
}
}
}
//! 没有找到,则默认输出第一个元素
return nums[0]
}
面试题42:连续子数组的最大和
题目一
思路一
思路二:分析数组的规律
代码
func maxSubArray(_ nums: [Int]) -> Int {
// 注意:result的初始值为第一个元素。
// 1. 创建变量
var result = nums[0] // result:连续子数组的最大和
var sum = 0 // sum:遍历数组元素和
for i in nums {
// 2. 如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字
if sum > 0 {
sum += i
}
// 3. 如果 sum <= 0,则说明 sum 对结果无增益效果,需要舍弃,则 sum 直接更新为当前遍历数字
else {
sum = i
}
// 3. 每次比较 sum 和 ans的大小,将最大值置为result,遍历结束返回结果
result = result >= sum ? result : sum
}
return result
}
思路三: 动态规划
代码
func maxSubArray(_ nums: [Int]) -> Int {
var numArray = nums
var res = numArray[0]
for index in 1 ..< numArray.count {
numArray[index] += max(0, numArray[index-1])
res = max(res, numArray[index])
}
return res
}
面试题45:把数组排成最小的数
题目一
思路一
代码
func minNumber(_ nums: [Int]) -> String {
// transfer to [String] type
var nums = nums.compactMap{"\($0)"}
// sort by compare combinations; O(nLogn)
nums.sort(by: {$0 + $1 < $1 + $0})
return nums.joined()
}
面试题51:数组中的逆序对
题目一
思路一
代码
class Solution {
func merge(_ nums: inout [Int], _ left: Int, _ mid: Int, _ right: Int, _ temp: inout [Int]) -> Int {
var i = left, j = mid + 1, k = 0
var count = 0
while i <= mid && j <= right {
if nums[i] <= nums[j] {
temp[k] = nums[i]
i+=1
count+=(j-mid-1)
} else {
temp[k] = nums[j]
j+=1
}
k+=1
}
while i <= mid {
temp[k] = nums[i]
i+=1
k+=1
count+=(j-mid-1)
}
while j <= right {
temp[k] = nums[j]
j+=1
k+=1
}
var l = left, t = 0
while l <= right {
nums[l] = temp[t]
l+=1
t+=1
}
return count
}
func reversePairs1(_ nums: inout [Int], _ left: Int, _ right: Int, _ temp: inout [Int]) -> Int {
guard left < right else { return 0 }
let mid = (left + right) / 2
let leftPairs = reversePairs1(&nums, left, mid, &temp)
let rightPairs = reversePairs1(&nums, mid+1, right, &temp)
if nums[mid] <= nums[mid+1] {
return leftPairs + rightPairs
}
let corssPairs = merge(&nums, left, mid, right, &temp)
return leftPairs + rightPairs + corssPairs
}
func reversePairs(_ nums: [Int]) -> Int {
var nums = nums
var temp = Array(repeating: 0, count: nums.count)
return reversePairs1(&nums, 0, nums.count - 1, &temp)
}
}
面试题56:数组中数字出现的次数
题目一
思路一
代码
func singleNumbers(_ nums: [Int]) -> [Int] {
var tmp = 0
for i in 0..<nums.count {
tmp ^= nums[i]
}
var n = 1
while (tmp & n) == 0 { //求最低位的1
n <<= 1
}
var a = 0
var b = 0
for i in 0..<nums.count {
if (nums[i] & n) != 0 {
a ^= nums[i]
}
else {
b ^= nums[i]
}
}
return [a, b]
}
题目二
思路一
- 时间复杂度:O(n)
- 空间复杂度:O(1)
思路二:哈希表
- 用一个哈希表来记录数组中每个数字出现的次数,但这个哈希表需要O(n)的空间。
- 时间复杂度:O(n)
- 空间复杂度:O(n)
代码
func singleNumber(_ nums: [Int]) -> Int {
// 1. 建立一个[Int:Int]字典,
var dict: [Int:Int] = [:]
// 2. 对数组进行遍历,有一个数就增加一个计数
for num in nums {
dict[num, default: 0] += 1
}
// 3. 最后遍历字典,返回找出计数为1的
for e in dict{
if e.value == 1 {
return e.key
}
}
return -1
}
面试题66:构建乘机数组
题目一
思路一
代码
func constructArr(_ a: [Int]) -> [Int] {
guard a.count > 0 else {
return []
}
let count = a.count
var left = 1
var result = [Int]()
for i in 0..<count {
result.append(left)
left *= a[i]
}
var right = 1
for i in (0..<count).reversed() {
result[i] *= right
right *= a[i]
}
return result
}