Swift 算法刷题

目标一周刷2道题
也不知道能坚持几天,这玩意在leetcode做完怎么保存啊

给一个有序的数组,数组中有重复数字,输入一个无序没有重复的数组
百度的一个面试题,被无序搞懵逼了,哎

class Solution {
    func test(_ nums: [Int]) -> [Int] {
        
        var result:[Int] = []
        var index = 0
        
        while index<nums.count {
            
            result.append(nums[index])
            
            index = index + 1
            
            while index<nums.count && nums[index] == nums[index-1] {
                index = index + 1
            }
            
        }
        
        
        index = 0
        let randomNumber:Int = Int(arc4random()) % result.count + 1
        var t:Int = result[index]
        while index + randomNumber < result.count {
            t = result[index]
            result[index] = result[index + randomNumber]
            result[index + randomNumber] = t
            index = index + randomNumber
        }
        
        return result
    }
}

136. 只出现一次的数字

任何数和 0 做异或运算,结果仍然是原来的数,即 a^0=a。
任何数和其自身做异或运算,结果是 0,即 a^a=0。
异或运算满足交换律和结合律,即 aba=baa=b(aa)=b⊕0=b。

/*
 [4,1,2,1,2]
 4 ^ 1 ^ 1 ^ 2 ^ 2
 4 0 0
 4
 */
class Solution {
    func singleNumber(_ nums: [Int]) -> Int {
        var result = 0
        
        for num in nums {
            result ^= num
            
            print(result)
        }
        
        return result
    }
}

70. 爬楼梯

经典动态规划题目
第一级台阶: 1种方法(爬一级)
第二级台阶: 2种方法(爬一级或爬二级)
第三级台阶: 从第一级再爬两级或者从第二级再爬一级 所以是1+2 3种方法
第四级台阶: 从第二级再爬两级或者从第三级再爬一级 所以是2+3 5种方法
第n级台阶:从第n-1爬1级或从第n-2爬2级
递推公式:Fn = Fn-1 + Fn-2

爬到每一级的方法看做一个状态

class Solution {
    func climbStairs(_ n: Int) -> Int {
        if n < 3 {
            return n
        }
        
      //记录n个状态,从1到n一次更新
        var dp = [0,1,2]
         
        for i in 3...n {
            dp.append(dp[i-1] + dp[i-2]) 
        }
        
        return dp[n]
    }
}

递归法
子问题 n=1 n=2

class Solution {
    func climbStairs(_ n: Int) -> Int {
        if n == 1 {
            return 1
        }
        if n == 2 {
            return 2
        }
        return climbStairs(n-1) + climbStairs(n-2)
    }
}

66. 加一

数字加法从最后一位开始,倒叙遍历
不是9,直接加1,不用进位
如果是9,变为0,向前遍历+1,直接return
如果遍历完,没有+1,证明全是9,首位补0

class Solution {
    func plusOne(_ digits: [Int]) -> [Int] {
        
        var digits = digits
        
        var index = digits.count - 1
        
        while index >= 0 {
            if digits[index] == 9 {
                digits[index] = 0
                index = index - 1
            }else{
                digits[index] = digits[index] + 1
                return digits
            }
        }
        
        digits.insert(1, at: 0)
        
        return digits
        
    }
}

35. 搜索插入位置

二分查找
关键字:有序,知道范围,待查找的数是整数
插入的位置pos,成立条件 nums[pos-1]<target<=nums[pos]

问题转化为在一个有序数组中找第一个大于等于target的下标

class Solution {
    func searchInsert(_ nums: [Int], _ target: Int) -> Int {
        var left = 0
        var right = nums.count - 1
        
        var result = nums.count
        
        while left <= right {

            let mid = (right - left)/2 + left
            
            if nums[mid] == target {
                return mid
            }else if nums[mid] < target {
                left = mid + 1
            }else{
                right = mid - 1
                result = mid
            }
        }
        
        return result
    }
}

26. 删除有序数组中的重复项

双指针
-关键字:原地修改
-模式识别:需要保存可覆盖位置和观测位置,利用双指针

i慢指针,指向答案位置
j快指针,用来扫描
当nums[j] != nums[I],找不到重复项,复制到i的位置,i向前

class Solution {
    //[1,1,3,4]
    //[1,3,3,4]
    //[1,3,4,4]
    // 相同 r+1  不同 做一次赋值 r+1  l+1
    func removeDuplicates(_ nums: inout [Int]) -> Int {
        if(nums.count<2){
            return nums.count
        }
        var left = 1
        var right = 1
        while right<nums.count {
            if nums[right-1] != nums[right]{
                nums[left] = nums[right]
                left+=1
            }
            right+=1
        }
        return left
    }
}

20. 有效的括号


先出现的左括号后匹配
模式识别:先进后出用栈

class Solution {
    func isValid(_ s: String) -> Bool {

        var stack:[Character] = []
        for char in s {
            
            if let t_char = stack.last,let c_char = change(char: char),t_char == c_char{
                stack.removeLast()
            }else{
                stack.append(char)
            }
        }
        
        return  stack.count==0 ? true : false
        
    }
    
    func change(char:Character) -> Character? {
        switch char {
        case ")":
            return "("
        case "]":
            return "["
        case "}":
            return "{"
        default:
            return nil
        }
    }
}

15. 三数之和

排序+双指针
双指针发

  • 关键字: 不可以包含重复
  • 模式识别: 利用排序避免重复答案
  • 降低复杂度变成 两数之和
  • 利用双指针找到所有的解,两个指针指向收尾,两数之和小于目标值,头向后移动,使得和增大 ,反之
class Solution {
    func threeSum(_ num: [Int]) -> [[Int]] {
        var result:[[Int]] = []
        
        var num = num
        num.sort()
        
        for (index,n) in num.enumerated() {
            //从小到大搜索,跳过重复值
            if index>0 && num[index] == num[index - 1] {
                continue
            }
            
            var left = index + 1
            
            var right = num.count - 1
            //三数之和 变为两数之和
            while left < right {
                
                let sum = n + num[left] + num[right]
                
                if sum > 0 {
                    repeat {
                        right = right - 1
                    }while right > 0 && right < num.count && num[right] == num[right + 1]
                }else{
                    if sum == 0 {
                        result.append([n,num[left],num[right]])
                    }
                    repeat {
                        left = left + 1
                    }while left > 0 && left < num.count && num[left] == num[left - 1]
                }
                
            }
        }
        return result
    }
}

13. 罗马数字转整数

class Solution {
    func romanToInt(_ s: String) -> Int {

        var str = s.replacingOccurrences(of: "CM", with: "a")
        str = str.replacingOccurrences(of: "CD", with: "b")
        str = str.replacingOccurrences(of: "XC", with: "c")
        str = str.replacingOccurrences(of: "XL", with: "d")
        str = str.replacingOccurrences(of: "IX", with: "e")
        str = str.replacingOccurrences(of: "IV", with: "f")

        let charArr:[Character] = Array(str)

        var index = charArr.count - 1

        var result = 0

        while index >= 0  {
            result = result + getVaule(char: charArr[index])
            index = index - 1
        }
        return result;
    }

    func getVaule(char:Character) -> Int {
        switch char {
        case "M":
            return 1000
        case "a":
            return 900
        case "D":
            return 500
        case "b":
            return 400
        case "C":
            return 100
        case "c":
            return 90
        case "L":
            return 50
        case "d":
            return 40
        case "X":
            return 10
        case "e":
            return 9
        case "V":
            return 5
        case "f":
            return 4
        case "I":
            return 1
        default:
            return -1
        }
    }
}

12. 整数转罗马数字

class Solution {
    func intToRoman(_ num: Int) -> String {
 
        let numArr = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
        let luomaArr = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
        
        var result = ""
        
        var t_index = 0
        
        var t_num = num
        
        while t_index < numArr.count {
            
            for index in t_index...(numArr.count-1) {
                
                if t_num >= numArr[index] {
                    result = result + luomaArr[index]
                    t_num = t_num - numArr[index]
                    break
                }else{
                    t_index = t_index + 1
                }
            }
        }
        
        return result
    }
}

11. 盛最多水的容器

class Solution {
    func maxArea(_ height: [Int]) -> Int {
        
        guard height.count > 1 else {
            return height.first ?? 0
        }
        
        var left = 0
        var right = height.count
        
        var result = 0
        
        while left != right {
            let t_result = min(height[left], height[right-1]) * (right-left - 1)
            
            if height[left] < height[right-1] {
                left = left + 1
            }else{
                right = right - 1
            }
            
            if t_result > result{
                result = t_result
            }
        }
        
        return result
    }
}

9. 回文数

class Solution {
    func isPalindrome(_ x: Int) -> Bool {
        
        if x>=0 && x<10 {
            return true
        }
        
        if x < 0 || x % 10 == 0{
            return false
        }
        
        
        var leftNumber = x
        var rightNumber = 0
        
        while !(leftNumber < rightNumber || leftNumber == rightNumber) {
            rightNumber = rightNumber * 10 + leftNumber%10
            leftNumber = leftNumber/10
        }
        
        return leftNumber == rightNumber || leftNumber == rightNumber/10
    }
}

7. 整数反转

class Solution {
    func reverse(_ x: Int) -> Int {

        var x:Int32 = Int32(x)
        var rev:Int32 = 0
        
        while x != 0 {
            
            let pushInt = push(x)
            
            if (x > 0 && rev > (Int32.max - pushInt)/10) || (x < 0 && rev < (Int32.max * -1 - pushInt)/10)  {
                rev = 0
            }
            else{
                rev = rev * 10 + pushInt
            }
            
            x = pop(x)
        }
//
//        rev * 10 + pushInt > Int32.max * -1
        
        return Int(rev)
    }
    
    
    func pop(_ x:Int32) -> Int32 {
        return x/10
    }
    
    func push(_ x:Int32) -> Int32 {
        return x%10
    }
    
}

将有序数组[1,3,5,7,9]和[2,4,6,8,10]合并为一个[1,2,3,4,5,6,7,8,9,10]

class Solution {
    func orderListMerage(_ list:[Int],_ list2:[Int]) -> [Int] {
       
        var index1 = 0
        var index2 = 0
        
        var result:[Int] = []
        
        while index1 < list.count && index2 < list2.count {
            if list[index1] < list2[index2] {
                result.append(list[index1])
                index1 += 1
            }else if list[index1] > list2[index2] {
                result.append(list2[index2])
                index2 += 1
            }else{
                result.append(list[index1])
                index1 += 1
                result.append(list2[index2])
                index2 += 1
            }
        }
        
        while index1 < list.count{
            result.append(list[index1])
            index1 += 1
        }
        
        while index2 < list2.count{
            result.append(list2[index2])
            index2 += 1
        }
        
        
        return result
    }
}

6. Z 字形变换

class Solution {
    func convert(_ s: String, _ numRows: Int) -> String {
        
        guard numRows>1 else { return s }
        
        var rows:[[Character]] = []
        for _ in 0..<min(numRows, s.count) {
            rows.append([Character]())
        }
        
        var curRow = 0
        var down = false
        
        for (char) in s {
            rows[curRow].append(char)
            if (curRow == 0 || curRow == numRows - 1){
                down = !down
            }
            curRow = down ? curRow + 1 : curRow - 1
        }
        
        var result:[Character] = []
        for charArr in rows {
            for char in charArr {
                result.append(char)
            }
        }
        
        return String(result)
    }
}

5. 最长回文子串

最长回文子串
中心扩散法
- 列举所有可能的回文子串的中心位置
- 中心位置可能是一个字符,也有可能是两个相邻的字符
- 记录最长回文子串的相关变量

class Solution {
    func longestPalindrome(_ s: String) -> String {

        guard s.count > 1 else {
            return s
        }

        var index = 0
        var left = 0
        var right = 1
        
        let arr = Array(s.utf8)

        while index<s.count {
            // 奇数
            let len1 = findStr(s: arr, left: index, right: index)
            // 偶数
            let len2 = findStr(s: arr, left: index, right: index+1)

            let len = max(len1, len2)

            if len > right - left {
                left = index-(len-1)/2
                right = left + len
            }
            index = index + 1
        }
        let index1 = s.index(s.startIndex, offsetBy: left)
        let index2 = s.index(s.startIndex, offsetBy: right)
        return String(s[index1..<index2])
    }

    //aaaaaa   index = 2 len 6 左移 2
    //aaaaa   index 2    len 5  左移2位
    //babbd
    //cbb
    //cbbd
    //babad
   // 向两边扩散,
    func findStr(s:[String.UTF8View.Element], left: Int,right: Int) -> Int {
        var t_left = left
        var t_right = right
        while t_left>=0 ,t_right < s.count,s[t_left] == s[t_right] {
            t_left = t_left - 1
            t_right = t_right + 1
        }
      // 回文子串不包含left和right,所以回文子串的长度
        return t_right - t_left - 1
    }
}

动态规划法
思路
一个回文长度大于2,去掉两头以后,剩下的部分依然是回文

4. 寻找两个正序数组的中位数

class Solution {
    func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double {
        
        var arr = nums1 + nums2
        
        arr.sort(by: >)
        
        let m = arr.count/2
        
        if arr.count%2 == 0 {
            return (Double(arr[m]) + Double(arr[m-1]))/2
        }else{
            return Double(arr[m])
        }
    }
}

3. 无重复字符的最长子串

class Solution {
    func lengthOfLongestSubstring(_ s: String) -> Int {
        
        guard s.count > 1 else {
            return s.count
        }
        
        var right = 1
        var left = 0
        var i = 0
        var result = 1
        
        let chars = Array(s.utf8)

        while right < chars.count {
            i = left
            while i < right {
                //用当前子串的最后一个,与前面每一个比较
                if chars[right] == chars[i]{
                    left = i + 1
                    break
                }
                i = i + 1
            }
            result = max(result,right-left+1)
            right = right + 1
        }
        
        return result
    }
}

2. 两数相加

public class ListNode {
    public var val: Int
    public var next: ListNode?
    public init() { self.val = 0; self.next = nil; }
    public init(_ val: Int) { self.val = val; self.next = nil; }
    public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; }
}

//输入:l1 = [2,4,3], l2 = [5,6,4]
//输出:[7,0,8]
//解释:342 + 465 = 807

class Solution {
    func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
        
        let header:ListNode = ListNode()
        
        var t_nextNode:ListNode = header
        
        var t = 0
        
        var t_l1:ListNode? = l1
        var t_l2:ListNode? = l2
        
        while t_l1 != nil || t_l2 != nil {
            if let t_t_l1 = t_l1 {
                t = t + t_t_l1.val
                t_l1 = t_t_l1.next
            }
            if let t_t_l2 = t_l2 {
                t = t + t_t_l2.val
                t_l2 = t_t_l2.next
            }
    
            t_nextNode.next = ListNode(t%10)
            t_nextNode = t_nextNode.next!
            
            t = t/10
            
            //t = 1
            //8 ,9 ,9,9 0, 0,,
        }
        
        if t > 0 {
            t_nextNode.next = ListNode(t)
        }
        
        return header.next
    }
}

1. 两数之和

查找表法

  • 在遍历的同时,记录一些信息,以省去一层循环,以空间换时间
  • 需要记录已经遍历过的数值和它所对应的下标,可以借助查找表实现
    查找表有两个常用的实现:
    哈希
    平衡二叉树

eg: nums = [6,3,8,2,1] target=8

map key 6 3 8 2
value 0 1 2
6 :8-6= 2, 2不在,存0
3 :8-3= 5, 5不在,存1
8 :8-8= 0, 0不在,存2
2 :8-2= 6, 6在,输出0,3

class Solution {
    /*
     2,7,11,15    9
    7:0
    */
    func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
        var dic:[Int:Int] = [:]
        var index = 0
        while index < nums.count{
            let num = nums[index]
            if dic[num] != nil {
                return [dic[num]!,index]
            }
            dic[target-num] = index
            index+=1
        }

        return [0,0]

    }
}

字符串翻转,给定字符串“hello,world”,实现将其翻转。输出结果:"dlrow,olleh"

class Solution {
    func reverse(_ str:String) -> String {
        guard str.count > 1 else { return str }
        
        var left = 0
        var right = str.count - 1
        
        var arr:[Character] = Array(str)
        
        while left<right {
            let temp = arr[right]
            arr[right] = arr[left]
            arr[left] = temp
            left += 1;
            right -= 1;
        }
        
        return String(arr)
    }
}

17. 电话号码的字母组合

方法1:深度优先搜索
-关键字:所有组合
-模式识别: 搜索算法
自顶向下的递归实现深搜
定义子问题(原问题简化后的问题)
在当前递归层结合子问题结果解决原问题

eg: 2:abc 3 def
给定的数字是2和3
原问题就是 2和3 对应的所有字母组合
子问题 3 对应的字母组合

解就是 将2对应的字母组合 放在3的前面

递归定义
第一步:定义递归出口
第二步:递归解决子问题
第三步:解决原问题

最后 主函数生成辅助参数,调用递归

class Solution {

    var result:[String] = []

    func letterCombinations(_ digits: String) -> [String] {
        guard digits.count>0 else {
            return []
        }
        let phoneMap = [
            "2":["a","b","c"],
            "3":["d","e","f"],
            "4":["g","h","i"],
            "5":["j","k","l"],
            "6":["m","n","o"],
            "7":["p","q","r","s"],
            "8":["t","u","v"],
            "9":["w","x","y","z"],
        ]
        self.solver(digits: digits, phoneMap: phoneMap)
        return result;
    }

    func solver(digits:String,phoneMap:[String:[String]],index:Int = 0,resultStr:String = "") {
        if index == digits.count{
            self.result.append(resultStr)
            return
        }

        let numbers = Array(digits)
        let number = String(numbers[index])
        let arr = phoneMap[number] ?? [];

        for str in arr {
            solver(digits: digits, phoneMap: phoneMap, index: index+1, resultStr: resultStr.appending(str))
        }
    }
}

17. 旋转数组

旋转的题,先写几个列子,找规律

class Solution {
    func rotate(_ nums: inout [Int], _ k: Int) {
        /*
         1234
         4321
         3421
         3412
         */
        let kk = k % nums.count
        reverse(&nums,left:0,right:nums.count-1)
        reverse(&nums,left:0,right:kk-1)
        reverse(&nums,left:kk,right:nums.count-1)
    }

    func reverse(_ nums:inout [Int], left:Int,right:Int){
        var tl = left
        var tr = right
        while tl<tr{
            let temp = nums[tl]
            nums[tl] = nums[tr]
            nums[tr] = temp
            tl+=1
            tr-=1
        }
    }
}

两个数组的交集 II

哈希映射

  • 将个数小的数组,进行哈希映射
  • key 值 vale 出现次数
    遍历数组nums2
    如果哈希存在,值为正,添加到结果里,值减一
class Solution {
    func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
        var result:[Int] = []
        let tnum = nums1.count <= nums2.count ? nums1 : nums2
        let xnum = nums1.count <= nums2.count ? nums2 : nums1
        var dic:[Int:Int] = [:]
        for num in tnum{
            dic[num] = (dic[num] != nil) ? (dic[num]! + 1) : 1
        }
        //[1:2]
        
        for num in xnum {
            if let t = dic[num],t>0 {
                result.append(num)
                dic[num] = t-1
            }
        }

        return result
    }
}

旋转图像

找规律
先上下交换
再左右交换

/*
13  14   15 16
 9  10   11 12
 5   6   7   8
 1   2   3   4
 */
class Solution {
    func rotate(_ matrix: inout [[Int]]) {
        var i = 0
        let lenght = matrix.count
        while i < lenght/2 {
            let t = matrix[i]
            matrix[i] = matrix[lenght-1-i]
            matrix[lenght-1-i] = t
            i+=1
        }

        i = 0
        
        while i < matrix.count {
            var j = i+1
            while j<matrix.count {
                let t = matrix[i][j]
                matrix[i][j] = matrix[j][i]
                matrix[j][i] = t
                j+=1
            }
            i+=1
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容