Skip to content

huituzidd/leetcode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 

Repository files navigation

1.两数之和

2.有效的括号

3.最大子序和

4.多数元素

5.买卖股票的最佳时机

6.找到所有数组中消失的数字

7.最短无序连续子数组

8.翻转二叉树

9.对称二叉树

10.合并二叉树

11.合并排序的数组

12.543.二叉树的直径

13.206.反转链表

14.反转字符串

15.两两交换链表中的节点

16.119.杨辉三角

[17.119. 杨辉三角 II](#17.119. 杨辉三角 II)

1.两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1]

解题思路: 利用hash的key-value键值对,将target-nums[当前下标]作为key查找,时间复杂度为O(n)

func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
        var targetNums = [Int : Int]();
            for i in 0..<nums.count {
                targetNums[nums[i]] = i
            }
            for j in 0..<nums.count {
                if targetNums[target - nums[j]] != nil && targetNums[target - nums[j]]! > 0 && j != targetNums[target - nums[j]]  {
                    return [j, targetNums[target - nums[j]]!]
                }
            }    
        return [0 , 0]
}

执行用时 : 36 ms, 在所有 Swift 提交中击败了98.81%的用户 内存消耗 :20.9 MB, 在所有 Swift 提交中击败了5.12%的用户

2.有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可被认为是有效字符串。 示例 1: 输入: "()" 输出: true 示例 2: 输入: "()[]{}" 输出: true 示例 3: 输入: "(]" 输出: false 示例 4: 输入: "([)]" 输出: false 示例 5: 输入: "{[]}" 输出: true

思路:一开始的想法是能不能通过判断个数去解决这个问题,发现这只是其中的一个条件,这个问题最重要的部分在于顺序,所以就想到了利用栈空间的先进后出的特性,利用循环将栈中的最后一个字符与字符串中的字符作比对,匹配到了就出栈,不匹配就入栈。代码如下:

class Solution {
    func isValid(_ s: String) -> Bool {
        if s == "" {
            return true
        } else if s.count % 2 != 0 {
            return false
        }
        
        var compareArray = (String(s[s.startIndex]))
        for i in 1..<s.count {
            //排除比较的数组中为空的情况
            if compareArray.count == 0 {
                compareArray.append(String(s[s.index(s.startIndex, offsetBy: i)]))
                continue;
            }
            
            if elemtentValid(String(compareArray.last!), String(s[s.index(s.startIndex, offsetBy: i)])) {
                compareArray.removeLast()
            } else {
                let compareString = String(s[s.index(s.startIndex, offsetBy: i)])
                if compareString == ")" || compareString == "]" || compareString == "}"  {
                    return false
                } else {
                    compareArray.append(compareString)
                }
            }
        }
        
        return compareArray.count == 0 ? true : false
    }
    
    func elemtentValid(_ d: String, _ c: String) -> Bool {
        if d + c == "()" || d + c == "[]" || d + c == "{}"  {
            return true;
        }
        return false;
    }
}

后面发现这个方法太繁琐了,因为自己swift语法不熟悉导致了各种判断,执行效率不高,后面看到一位大神的swift代码,觉得很好,代码如下:

class Solution {
    func isValid(_ s: String) -> Bool {
        var stack = [Character]()
        
        for (_, char) in s.enumerated() {
            if let topChar = stack.last {
                if  (topChar == ("(") as Character && char == (")") as Character) ||
                    (topChar == ("[") as Character && char == ("]") as Character) ||
                    (topChar == ("{") as Character && char == ("}") as Character){
                    stack.removeLast();
                }
                else {
                    stack.append(char);
                }
            }
            else {
                stack.append(char);
            }
        }
        
        return stack.isEmpty
    }
}

思路清晰,简洁。 膜拜。

3.最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

思路:

for循环遍历,用数组第0个元素与0+1的元素比,取最大值,得到的值与0+1+2的元素再比,以此类推

class Solution {
    func maxSubArray(_ nums: [Int]) -> Int {
        var maxNum = nums[0]
        var sum = 0
        for i in 0..<nums.count {
            if sum > 0 {
                sum += nums[i]
            } else {
                sum = nums[i]
            }
            maxNum = max(maxNum, sum)
        }
        return maxNum
    }
}

4.多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [3,2,3] 输出: 3

示例 2:

输入: [2,2,1,1,1,2,2] 输出: 2

思路:一开始想的是暴力遍历,用每一个元素的count值和[n/2]对比返回,代码如下:

class Solution {
    func majorityElement(_ nums: [Int]) -> Int {
        for num in nums {
            var sum = 0
            for i in nums {
                if num == i {
                    sum += 1
                }
            }
            
            if sum > nums.count / 2 {
                return num
            }
        }
        return -1
    }
}

但是执行完以后提交,结果执行结果超出时间限制。。。后面看到了先排序后找众数的想法,很简洁,拿到有序数组的第n/2个元素就是结果。代码如下:

class Solution {
    func majorityElement(_ nums: [Int]) -> Int {
        let array = nums.sorted()
        return array[nums.count / 2]
    }
}

然后又看到了摩尔投票法,思路就是如果把该众数记为+1,把其他数记为−1,将它们全部加起来,和是大于 0 的。那么开始定义一个当前的元素tempNum和当前的和count,遍历当前数组,如果tempNum与数组元素相同则加一,不同则减一,如果count等于0,则将数组元素赋值给tempNum,count加一。代码如下:

class Solution {
    func majorityElement(_ nums: [Int]) -> Int {
        var tempNum = 0
        var count = 0
        for num in nums {
            if count == 0 {
                tempNum = num
                count += 1
            } else if tempNum == num {
                count += 1
            } else {
                count -= 1
            }
        }
        return tempNum
    }
}

5.买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

示例 1:

输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 示例 2:

输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

思路:

其实就是找逆差最大。定义一个最大逆差值reg,一个最小值minPrice,遍历数组元素与minPrice做差值,与reg取最大值,最后得到的数字就是最大利润。代码如下:

class Solution {
    func maxProfit(_ prices: [Int]) -> Int {
        if prices.isEmpty {
            return 0
        }
        var reg = 0
        var minPrice = prices[0]
        for i in 1..<prices.count {
            if minPrice > prices[i] {
                minPrice = prices[i]
            } else {
                reg = max(prices[i] - minPrice, reg)
            }
        }
        return sum
    }
}

6.找到所有数组中消失的数字

给定一个范围在  1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。

找到所有在 [1, n] 范围之间没有出现在数组中的数字。

您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。

示例:

输入: [4,3,2,7,8,2,3,1]

输出: [5,6]

思路:一开始想的是给数组排序,然后判断nums[i]+1和nums[n+1]是否相等,不相等就是没出现的数字。然后又想到了直接给nums[nums[i] - 1]置为1,然后遍历数组,不是1的就是不存在的。代码如下:

class Solution {
    func findDisappearedNumbers(_ nums: [Int]) -> [Int] {
        var array = Array(repeating: 0, count: nums.count)
        var resultArray = [Int]()
        for i in 0..<array.count {
            array[nums[i] - 1] = 1
        }
        for i in 0..<array.count {
            if array[i] != 1 {
                resultArray.append(i+1)
            }
        }
        return resultArray
    }
}

7.最短无序连续子数组

给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

你找到的子数组应是最短的,请输出它的长度。

示例 1:

输入: [2, 6, 4, 8, 10, 9, 15] 输出: 5 解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。 说明 :

1.输入的数组长度范围在 [1, 10,000]。 2.输入的数组可能包含重复元素 ,所以升序的意思是<=。

思路:一开始的想法是遍历两次,根据元素大小来判断左右边界,最后想了一下,可以把遍历两次变成一次操作来完成,代码如下:

class Solution {
    func findUnsortedSubarray(_ nums: [Int]) -> Int {
        var max = nums[0];
        var min = nums[nums.count-1];
        var l = 0, r = -1;
        for i in 0..<nums.count {
            if(max>nums[i]){
                r = i;
            }else{
                max = nums[i];
            }
            if(min<nums[nums.count-i-1]){
                l = nums.count-i-1;
            }else{
                min = nums[nums.count-i-1];
            }
        }
        return r-l+1;
    }
}

8.翻转二叉树

翻转一棵二叉树。

示例:

输入:

 4
/   \
2     7
/ \   / \
1   3 6   9

输出:

 4
/   \
7     2
/ \   / \
9   6 3   1

备注: 这个问题是受到 Max Howell 的 原问题 启发的 : 谷歌:我们90%的工程师使用您编写的软件(Homebrew),但是您却无法在面试时在白板上写出翻转二叉树这道题,这太糟糕了。

经典的反转二叉树来了。。。。

代码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public var val: Int
 *     public var left: TreeNode?
 *     public var right: TreeNode?
 *     public init(_ val: Int) {
 *         self.val = val
 *         self.left = nil
 *         self.right = nil
 *     }
 * }
 */
class Solution {
    func invertTree(_ root: TreeNode?) -> TreeNode? {
        if root == nil {
            return nil
        }
        let left: TreeNode? = invertTree(root!.left)
        let right: TreeNode? = invertTree(root!.right)
        root!.right = left
        root!.left = right
        return root
    }
}

9.对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

思路:看到这个就想起直接递归,只要同一层级的左右子树相等,那么就是对称二叉树,代码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public var val: Int
 *     public var left: TreeNode?
 *     public var right: TreeNode?
 *     public init(_ val: Int) {
 *         self.val = val
 *         self.left = nil
 *         self.right = nil
 *     }
 * }
 */
class Solution {
    func isSymmetric(_ root: TreeNode?) -> Bool {
        return isMirror(root, root)
    }
    
    func isMirror(_ root1: TreeNode?,_ root2: TreeNode?) -> Bool {
        if root1 == nil && root2 == nil {
            return true
        }
        if root1 == nil || root2 == nil {
            return false
        }
        return root1?.val == root2?.val && isMirror(root1?.left, root2?.right) && isMirror(root1?.right, root2?.left)
    }
}

10.合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

输入:

    Tree 1                     Tree 2                  
          1                         2                             
         / \                       / \                            
        3   2                     1   3                        
       /                           \   \                      
      5                             4   7         

输出: 合并后的树:

         3
        / \
       4   5
      / \   \ 
     5   4   7

注意: 合并必须从两个树的根节点开始。

思路:看到这个就直接想到递归相加,判断边界条件。代码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public var val: Int
 *     public var left: TreeNode?
 *     public var right: TreeNode?
 *     public init(_ val: Int) {
 *         self.val = val
 *         self.left = nil
 *         self.right = nil
 *     }
 * }
 */
class Solution {
    func mergeTrees(_ t1: TreeNode?, _ t2: TreeNode?) -> TreeNode? {
        if t1 == nil && t2 == nil {
            return nil
        } else if t1 == nil {
            return t2
        } else if t2 == nil {
            return t1
        }
        let sum = TreeNode(t1!.val + t2!.val)
        sum.left = mergeTrees(t1?.left, t2?.left)
        sum.right = mergeTrees(t1?.right, t2?.right)
        return sum
    }
}

11.合并排序的数组

给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。

初始化 A 和 B 的元素数量分别为 m 和 n。

示例:

输入:

A = [1,2,3,0,0,0], m = 3

B = [2,5,6], n = 3

输出: [1,2,2,3,5,6]

说明:

A.length == n + m

思路:由于两个数组已经排序,所以经过遍历,将两个数组最小的值比对,将最小的值放入新数组中。代码如下:

class Solution {
    func merge(_ A: inout [Int], _ m: Int, _ B: [Int], _ n: Int) {
        var sort = [Int]()
        var indexa = 0
        var indexb = 0
        while indexa < m || indexb < n {
            if indexa == m {
                sort.append(B[indexb])
                indexb += 1
            } else if indexb == n {
                sort.append(A[indexa])
                indexa += 1
            } else if A[indexa] < B[indexb] {
                sort.append(A[indexa])
                indexa += 1
            } else {
                sort.append(B[indexb])
                indexb += 1
            }
        }
        A = sort
    }
}

12. 543.二叉树的直径

给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。

示例 : 给定二叉树

          1
         / \
        2   3
       / \     
      4   5

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

注意:两结点之间的路径长度是以它们之间边的数目表示。

思路:深度优先搜索,计算y左右子树的最大层级相加+1即为直径。代码如下:

class Solution {
    var maxNumber = 0
    func diameterOfBinaryTree(_ root: TreeNode?) -> Int {
        depth(root)
        return maxNumber
    }
    func depth(_ node: TreeNode?) -> Int {
        if node == nil {
            return 0
        }
        let left = depth(node?.left)
        let right = depth(node?.right)
        maxNumber = max(left + right, maxNumber)
        return max(left, right) + 1
    }
}

13. 206.反转链表

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
class Solution {
    func reverseList(_ head: ListNode?) -> ListNode? {
        guard var headNode = head else {
            return nil
        }
        let list = ListNode.init(headNode.val)
        var newHead = list
        while let next = headNode.next {
            let newNode = ListNode.init(next.val)
            newNode.next = newHead
            newHead = newNode
            headNode = next
        }
        return newHead
    }
}

14.反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

示例 1:

输入:["h","e","l","l","o"] 输出:["o","l","l","e","h"]

示例 2:

输入:["H","a","n","n","a","h"] 输出:["h","a","n","n","a","H"]

(递归实现)

class Solution {
    func reverseString(_ s: inout [Character]) {
        helper(&s, 0, s.count - 1)
    }
    
    func helper(_ s: inout [Character], _ leftIndex: Int, _ rightIndex: Int) -> [Character] {
        if leftIndex >= rightIndex {
            return s
        }
        let temp: Character = s[leftIndex]
        s[leftIndex] = s[rightIndex]
        s[rightIndex] = temp
        return helper(&s, leftIndex+1, rightIndex-1)
    }
}

15.两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

(递归实现)

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.
public class ListNode {
    public var val: Int
    public var next: ListNode?
    public init(_ val: Int) {
        self.val = val
        self.next = nil
    }
}

class Solution {
    func swapPairs(_ head: ListNode?) -> ListNode? {
        if head == nil || head?.next == nil {
            return head
        }
        
        let firstNode = head
        let secondNode = head?.next
        
        firstNode?.next = swapPairs(secondNode?.next)
        secondNode?.next = firstNode
        
        return secondNode;
    }
}

16.119.杨辉三角

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 5 输出:

[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]
class Solution {
    func generate(_ numRows: Int) -> [[Int]] {
        guard numRows > 0 else {
            return []
        }
        
        var array = [[Int]]()
        array.append([1])
        
        for i in 1..<numRows {
            var row = [Int]()
            let preRow = array[i - 1]
            
            row.append(1)
            for j in 1..<i {
                row.append(preRow[j - 1] + preRow[j])
            }
            
            row.append(1)
            array.append(row)
            
        }
        return array
    }
}

17.119. 杨辉三角 II

给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 3 输出: [1,3,3,1]

class Solution {
    func getRow(_ rowIndex: Int) -> [Int] {
        if rowIndex == 0 {
            return [1]
        }
        var pre = 1;
        var cur = [Int]();
        cur.append(1);
        
        for  i in 1...rowIndex {
            for j in 1..<i {
                let temp = cur[j]
                cur[j] = pre + cur[j]
                pre = temp
            }
            cur.append(1)
        }
        return cur
    }
}

About

plan for leetcode

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages