第一周LeetCode记录

9.7 1.两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

思路一

遍历数组,拿sum去减遍历的数,判断是否存在,存在返回下标

思路二

先排序,首尾相加,若大于target,right-1,小于target,left+1

我的解法:

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        new_nums = sorted(nums)
        left = 0
        right = len(nums) - 1

        while new_nums[left] + new_nums[right] != target:

            if left == right:
                print("无结果")
                break

            elif new_nums[left] + new_nums[right] > target:
                right -= 1
            else:
                left += 1

        if new_nums[left] == new_nums[right]:
            start = nums.index(new_nums[left])
            end = nums.index(new_nums[right], left + 1, len(new_nums))

        else:
            start = nums.index(new_nums[left])
            end = nums.index(new_nums[right])

        return sorted([start,end])

错误总结:

1. 在list.index()方法中,忽略了两个相等的值下标一样。就要从后面找end。
2. 结尾排序,重要!

最优解:

为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法是什么?哈希表。

通过以空间换取速度的方式,我们可以将查找时间从 O(n)O(n) 降低到 O(1)O(1)。哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到 O(n)O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)O(1)。

一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i]target−nums[i])是否存在于表中。注意,该目标元素不能是 nums[i]nums[i] 本身!

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], i);
        }
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (map.containsKey(complement) && map.get(complement) != i) {
                return new int[] { i, map.get(complement) };
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}



最优解总结:

  • 利用hash存储index和value,在原list中直接找
  • 因为题设中暗含了不可能有3个同样的数,所以此解法巧妙的不用考虑重复键值对的问题。

9.8 2. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。

思路

递归,每次调用本身,直至符合条件。并且每次存储算出来的数,如果出现过返回false。

我的解法:

class Solution:
    all_list = []

    @classmethod
    def isHappy(cls, n: int) -> bool:
        if n in Solution.all_list:
            return False

        li = list(str(n))
        sum = 0
        for i in li:
            sum += int(i) * int(i)
        if sum != 1:
            Solution.all_list.append(n)
            boolean = Solution.isHappy(sum)
            return boolean
        else:
            return True

错误总结:

  1. 解法貌似没问题,但是leetcode不支持。
  2. 因为用的是递归,不知道怎么在方法里记录已有数据

最优解:

class Solution:
    def isHappy(self, n: int) -> bool:
        seen = {1}
        while n not in seen:
            seen.add(n)
            n = sum(int(i) ** 2 for i in str(n))
        return n == 1

总结:

没有用递归调用此方法,所以不会出现无法记录的情况。另外,用set来记录,达到记录的目的。

9.9 3.排列硬币

你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。

给定一个数字 n,找出可形成完整阶梯行的总行数。

n 是一个非负整数,并且在32位有符号整型的范围内。

n = 5

硬币可排列成以下几行:
¤
¤ ¤
¤ ¤

因为第三行不完整,所以返回2

思路

观察棋子总数和行数的关系

我的解法

class Solution:
    def arrangeCoins(self, n: int) -> int:
        if n == 0:
            return 0
        elif n == 1:
            return 1
        else:
            for i in range(1,n+1):
                if (1 + i) * i / 2 == n:
                    return i
                elif (1 + i) * i / 2 < n:
                    continue
                else:
                    return i-1

错误总结

当等于n的时候可以直接返回行数。

0,1是特殊情况没有考虑到

最优解

class Solution:
    def arrangeCoins(self, n: int) -> int:
        return int((2*n+1/4)**0.5-1/2)

n列一共需要(1+n)*n/2个棋子,y = (1+n)*n/2 => 2y + 1/4 = n^2 + n + 1/4 => 2y + 1/4 = (n+1/2)^2
=> 换成n=f(y)表示

总结:

x, y之间有联系,可以先建立函数关系式,通过关系式来完成相互之间转化。

9.12 4. 猜数字

小A 和 小B 在玩猜数字。小B 每次从 1, 2, 3 中随机选择一个,小A 每次也从 1, 2, 3 中选择一个猜。他们一共进行三次这个游戏,请返回 小A 猜对了几次?

输入:guess = [1,2,3], answer = [1,2,3]
输出:3
解释:小A 每次都猜对了。

思路

两个数组索引的数字比较

我的解法:

    def game(self, guess: list, answer: list) -> int:
        sum = 0
        for i in range(3):
            if guess[i] == answer[i]:
                sum += 1
        return sum

最优解

return sum(guess[i]==answer[i] for i in range(len(guess)))

总结

可以对bool求和。

9.12 5.珠玑妙算

计算机有4个槽,每个槽放一个球,颜色可能是红色(R)、黄色(Y)、绿色(G)或蓝色(B)。例如,计算机可能有RGGB 4种(槽1为红色,槽2、3为绿色,槽4为蓝色)。作为用户,你试图猜出颜色组合。打个比方,你可能会猜YRGB。要是猜对某个槽的颜色,则算一次“猜中”;要是只猜对颜色但槽位猜错了,则算一次“伪猜中”。注意,“猜中”不能算入“伪猜中”。

给定一种颜色组合solution和一个猜测guess,编写一个方法,返回猜中和伪猜中的次数answer,其中answer[0]为猜中的次数,answer[1]为伪猜中的次数。

输入: solution="RGBY",guess="GGRR"
输出: [1,1]
解释: 猜中1次,伪猜中1次。

思路

两个列表取交集可以得到伪猜中数量,用猜数字的算法得到猜中数量,伪猜中减去猜中

我的解法(未解出来):

伪猜中没有想到要利用hash来记录,值作为键,出现的次数作为值。取交集可以获取。

错误总结:

  1. 伪猜中的算法错误。

最优解

class Solution:
    def masterMind(self, solution: str, guess: str):
        from collections import Counter
        total = sum((Counter(solution) & Counter(guess)).values())
        right = sum(1 for (i, j) in zip(solution, guess) if i == j)
        return [right, total - right]

总结:

Couter可以返回每个元素出现了几次,并且可以取交集等操作,获得伪猜中次数。要复习一下cookbook里面的常用工具类方法。

9.13 6.判断能否形成等差数列

给你一个数字数组 arr 。

如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为 等差数列 。

如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false 。

思路

先将数组排序,遍历后一项减前一项得到差,差值不变返回true。

我的解法

        if len(arr) == 2:
            return True
        if len(arr) < 2:
            return False
        arr.sort()
        a = arr[1] - arr[0]
        for i in range(len(arr)-1):
            b = arr[i+1] - arr[i]
            if b != a:
                return False
        return True

最优解

class Solution:
    def canMakeArithmeticProgression(self, arr: List[int]) -> bool:
        arr.sort()
        a=[arr[i+1]-arr[i] for i in range(len(arr)-1)]
        if len(set(a))==1:
            return True
        else:
            return False

总结:

利用列表解析式可以得到一个列表,里面元素是差值,判断差值是否一样就用set去重。

posted @ 2020-09-13 11:31  Jimmyhe  阅读(129)  评论(0编辑  收藏  举报