• 第五周LeetCode记录


    10.13 21. 1位重复数字

    给定正整数 N,返回小于等于 N 且具有至少 1 位重复数字的正整数的个数。

    输入:20
    输出:1
    解释:具有至少 1 位重复数字的正数(<= 20)只有 11 。
    
    输入:100
    输出:10
    解释:具有至少 1 位重复数字的正数(<= 100)有 11,22,33,44,55,66,77,88,99 和 100 。
    
    输入:1000
    输出:262
    

    最优解

    public int numDupDigitsAtMostN(int N) {
            return N - dp(N);
        }
    
        public int dp(int n) {
            List<Integer> digits = new ArrayList<>();
            while (n > 0) {
                digits.add(n % 10);
                n /= 10;
            }
            // k代表k的位数
          	// 设剩下的位置为i,剩下的数字为j,则不重复数字是在每一位依次填入与前几位不同的数字,
            // 即选取剩下的j个数字填入剩下的i个位置,即有A(j, i)种可能,最后将其累加就是不重复数字个数
            int k = digits.size();
    
            int[] used = new int[10];
            int total = 0;
    				
            // 求位数小于k的不重复数字的个数:因为最高位总是为0,
            // 因此一开始剩下的数字j总是为9个(1-9),然后剩下的低位可选的数字总共有A(10-1,i)
            for (int i = 1; i < k; i++) {
                total += 9 * A(9, i - 1);
            }
    
          	// 位数等于k
            for (int i = k - 1; i >= 0; i--) {
                int num = digits.get(i);
    
                for (int j = i == k - 1 ? 1 : 0; j < num; j++) {
                    if (used[j] != 0) {
                        continue;
                    }
                    total += A(10 - (k - i), i);
                }
    
                if (++used[num] > 1) {
                    break;
                }
    
                if (i == 0) {
                    total += 1;
                }
            }
            return total;
        }
    
        public int fact(int n) {
            if (n == 1 || n == 0) {
                return 1;
            }
            return n * fact(n - 1);
        }
    
        public int A(int m, int n) {
            return fact(m) / fact(m - n);
        }
    

    总结

    为什么要用反证法:可以用公式计算比较方便,排列组合。分情况讨论,一种是高位为0,一种是高位不为0.

    10.14 22. 找不同

    给定两个字符串 st,它们只包含小写字母。

    字符串 *t* 由字符串 *s* 随机重排,然后在随机位置添加一个字母。

    请找出在 t 中被添加的字母。

    输入:s = "abcd", t = "abcde"
    输出:"e"
    解释:'e' 是那个被添加的字母
    
    输入:s = "", t = "y"
    输出:"y"
    

    思路

    用collections.Count统计各个字幕出现的次数,找出多的那一个。

    我的解

    class Solution:
        @classmethod
        def findTheDifference(self, s: str, t: str) -> str:
            from collections import Counter
            counter_1 = Counter(t)
            counter_1.subtract(s)
            for k,v in counter_1.items():
                if v == 1:
                    return k
                    
    

    10.14 23. 判断子序列

    给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

    你可以认为 s 和 t 中仅包含英文小写字母。字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符串(长度 <=100)。

    字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

    示例 1:
    s = "abc", t = "ahbgdc"
    
    返回 true.
    
    示例 2:
    s = "axc", t = "ahbgdc"
    
    返回 false
    

    思路

    双指针算法

    最优解

    class Solution:
        @classmethod
        def isSubsequence(self, s: str, t: str) -> bool:
            len_s = len(s)
            len_t = len(t)
            i = j = 0
            while i < len_s and j < len_t:
                if s[i] == t[j]:
                    i += 1
                j += 1
            return i == len_s
    

    总结

    利用双指针来判断子序列,切忌用遍历。

    10.15 24. 在排序数组中查找元素第一个和最后一个位置

    给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

    你的算法时间复杂度必须是 O(log n) 级别。

    如果数组中不存在目标值,返回 [-1, -1]。

    输入: nums = [5,7,7,8,8,10], target = 8
    输出: [3,4]
    
    输入: nums = [5,7,7,8,8,10], target = 6
    输出: [-1,-1]
    

    思路

    双指针,分别从前后逐个遍历。

    我的解

    class Solution:
        def searchRange(self, nums: List[int], target: int) -> List[int]:
            if len(nums) == 0:
                return [-1, -1]
            if len(nums) == 1:
                if nums[0] == target:
                    return [0,0]
    
            i = 0
            j = len(nums) - 1
    
            res = [-1] * 2
            while i < len(nums) and i != j:
                if nums[i] == target:
                    res[0] = i
                    while nums[j] != target:
                        j -= 1
                    res[-1] = j
                    return res
                else:
                    i += 1
                            
            if i == j and nums[i] == target:
                return [i,j]
                
            return res
            
      优化
      class Solution:
        def searchRange(self, nums, target):
            # find the index of the leftmost appearance of `target`. if it does not
            # appear, return [-1, -1] early.
            for i in range(len(nums)):
                if nums[i] == target:
                    left_idx = i
                    break
            else:
                return [-1, -1]
    
            # find the index of the rightmost appearance of `target` (by reverse
            # iteration). it is guaranteed to appear.
            for j in range(len(nums)-1, -1, -1):
                if nums[j] == target:
                    right_idx = j
                    break
    
            return [left_idx, right_idx]
    
    

    最优解

    class Solution:
        # returns leftmost (or rightmost) index at which `target` should be inserted in sorted
        # array `nums` via binary search.
        def extreme_insertion_index(self, nums, target, left):
            lo = 0
            hi = len(nums)
    
            while lo < hi:
                mid = (lo + hi) // 2
                if nums[mid] > target or (left and target == nums[mid]):
                    hi = mid
                else:
                    lo = mid+1
    
            return lo
    
    
        def searchRange(self, nums, target):
            left_idx = self.extreme_insertion_index(nums, target, True)
    
            # assert that `left_idx` is within the array bounds and that `target`
            # is actually in `nums`.
            if left_idx == len(nums) or nums[left_idx] != target:
                return [-1, -1]
    
            return [left_idx, self.extreme_insertion_index(nums, target, False)-1]
    

    总结

    因为题设排序数组,即可以使用二分法查找。

    10.18 25. 超级丑数

    编写一段程序来查找第 *n* 个超级丑数。

    超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。

    输入: n = 12, primes = [2,7,13,19]
    输出: 32 
    解释: 给定长度为 4 的质数列表 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。
    

    思路

    见下一题思路

    我的解

    class Solution:
        def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int:
            pointer_list = [0] * len(primes)
            res = [0] * n
            res[0] = 1
    
            for i in range(1, len(res)):
                res[i] = min(primes[j] * res[pointer_list[j]] for j in range(len(primes)))
                for index, value in enumerate(primes):
                    if res[i] == value * res[pointer_list[index]]:
                        pointer_list[index] += 1
            return res[-1]
    

    10.18 26. 下一个丑数

    编写一个程序,找出第 n 个丑数。

    丑数就是质因数只包含 2, 3, 5正整数

    输入: n = 10
    输出: 12
    解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
    

    最优解

    解法一:动态规划

    此题丑数就是2,3,5的排列组合所能组成的公倍数由小到大排成的数组

    class Solution:
        @classmethod
        def nthUglyNumber(self, n: int) -> int:
            i2 = i3 = i5 = 0
            dp = [0] * n
            dp[0] = 1
            for i in range(1, len(dp)):
                dp[i] = min(dp[i2] * 2, dp[i3] * 3, dp[i5] * 5)
                if dp[i] == dp[i2] * 2:
                    i2 += 1
                if dp[i] == dp[i3] * 3:
                    i3 += 1
                if dp[i] == dp[i5] * 5:
                    i5 += 1
            return dp[-1]
    
    
    if __name__ == '__main__':
        res = Solution.nthUglyNumber(10)
        print(res)
    

    点击查看算法动画

    解法二:堆算法
    from heapq import heappop, heappush
    class Ugly:
        def __init__(self):
            seen = {1, }
            self.nums = nums = []
            heap = []
            heappush(heap, 1)
    
            for _ in range(1690):
                curr_ugly = heappop(heap)
                nums.append(curr_ugly)
                for i in [2, 3, 5]:
                    new_ugly = curr_ugly * i
                    if new_ugly not in seen:
                        seen.add(new_ugly)
                        heappush(heap, new_ugly)
        
    class Solution:
        u = Ugly()
        def nthUglyNumber(self, n):
            return self.u.nums[n - 1]
    

    总结

    丑数的定义要明确,是所给质因子公倍数的排序数组。

  • 相关阅读:
    OpenCV几种边缘检测的简例
    OpenCV人脸检测并把图片写成avi视频
    cvFindContours函数
    cvSmooth函数 和 OpenCV自带的人脸检测
    用OpenCV进行视频截取
    论文笔记 Network In Network
    论文笔记 Unsupervised Learning by Predicting Noise
    论文笔记 Spatial contrasting for deep unsupervised learning
    源码分析 Large-Margin Softmax Loss for Convolutional Neural Networks
    Caffe代码分析--crop_layer.cu
  • 原文地址:https://www.cnblogs.com/jimmyhe/p/13873375.html
Copyright © 2020-2023  润新知