算法通关手册 刷题笔记1 数组基础

Posted 临风而眠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法通关手册 刷题笔记1 数组基础相关的知识,希望对你有一定的参考价值。

算法通关手册 刷题笔记1 数组基础

持续更新中

文章目录

数组操作题目

题号标题题解标签难度
0189轮转数组Python数组中等
0066加一Python数组简单
0724寻找数组的中心下标Python数组简单
0485最大连续 1 的个数Python数组简单
0238除自身以外数组的乘积Python数组中等

0189 轮转数组

AC

自己的解法

  • 一开始犯了错误:注意python中数组的赋值

    • 两个列表list1和list2,直接用等号赋值,list2修改后,list1也会被修改

      • 想要不改变原列表,使用[:]或者.copy()
    • 参考:python把一个数组赋值给另一个数组

    • 一开始的错误代码

      def rotate2( nums, k):
              """
              :type nums: List[int]
              :type k: int
              :rtype: None Do not return anything, modify nums in-place instead.
              """
              nums2 = nums
              for i in range(len(nums)):
                  nums2[i] =  nums[(i+k+1)%len(nums)]
      
              return nums2
      rotate2([1,2,3,4,5,6,7],3)
      
      [5, 6, 7, 5, 6, 7, 5]
      

      来分析一下: nums2[0] = nums[4] , 这时候 nums2[0]和nums[0]都变成了5 ,所以nums2[3] = nums[0] = 5…

  • 改了改,以为自己做对了,但是没AC

    def rotate(nums, k):
            """
            :type nums: List[int]
            :type k: int
            :rtype: None Do not return anything, modify nums in-place instead.
            """
            # nums2 = num
            nums2 = []
            for i in range(len(nums)):
                nums2.append(0)
            for i in range(len(nums)):
            #下面这俩应该都可以
    **            nums2[i] = nums[(i+k+1) % len(nums)]
                # nums2[(i+k)%len(nums)] =  nums[i]**
            return nums2
    rotate([1,2,3,4,5,6,7],3)
    
    [5, 6, 7, 1, 2, 3, 4]    
    

    难绷,审题! 去掉return就行了

其他解法

  • 算法通关手册上的python解法

    class Solution:
        def rotate(self, nums: List[int], k: int) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            n = len(nums)
            k = k % n
            self.reverse(nums, 0, n-1)
            self.reverse(nums, 0, k-1)
            self.reverse(nums, k, n-1)
        
        def reverse(self, nums: List[int], left: int , right: int) -> None:
            while left < right:
                tmp = nums[left]
                nums[left] = nums[right]
                nums[right] = tmp
                left += 1
                right -=1
    
  • 力扣题解区上面看到切片的解法,感觉very smart

    class Solution:
        def rotate(self, nums: List[int], k: int) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            k = k % len(nums)
            nums[:] = nums[-k:] + nums[:-k]
    

知识点查漏补缺

关于python中的数组赋值

python中对象的引用

0066 加一

AC

自己的解法

  • 一开始写的代码

    class Solution:
        def plusOne(self, digits: List[int]) -> List[int]:
            k = len(digits)
            sum = 0
            m = 1
            while k >= 1:
                sum += m*digits[k-1]
                m *= 10
                k -= 1
            newlis = []
            sum += 1
            j = 0
            while sum > 0:
    
                # newlis.append(sum % 10)
                newlis.insert(j, sum % 10)
                sum //=10
            return newlis
    

其他解法

  • 看《算法通关手册》的题解

    • 感觉思路很清晰

      有可能有进位,先在前面放个0,末位加个1,啥时候会有进位呢,那个位置上的数字为10的时候,如果低位都没碰到10,那么高位肯定不会碰到10,直接break,返回原来的列表,即现在的digits[1:]

      哪一位有进位,就把那一位变成0,然后它的前一位+1

      如果会一直进位到最高位,那么就返回digits

      def plusOne(self, digits: List[int]) -> List[int]:
          digits = [0] + digits
          digits[len(digits)-1] += 1
          for i in range(len(digits)-1,0,-1):
              if digits[i] != 10:
                  break
              else:
                  digits[i] = 0
                  digits[i-1] += 1
              
          if digits[0] == 0:
              return digits[1:] 
          else:
              return digits
      
    • 注意 [0] + digits的顺序是有影响的

  • 力扣官方题解 妙啊

    • 思路

      • 找出最长的后缀9
        • 如果 $\\textitdigits $的末尾没有 999,例如 [1,2,3],那么我们直接将末尾的数加一,得到 [1, 2, 4]并返回;
        • 如果 digits \\textitdigits digits 的末尾有若干个 9,例如 [1,2,3,9,9]那么我们只需要找出从末尾开始的第一个不为 999的元素,即 333,将该元素加一,得到 [1,2,4,9,9]]。随后将末尾的 999 全部置零,得到 [1,2,4,0,0]并返回。
        • 如果 digits \\textitdigits digits 的所有元素都是 999,例如 [9,9,9,9,9],那么答案为 [ 1 , 0 , 0 , 0 , 0 , 0 ] [1, 0, 0, 0, 0, 0] [1,0,0,0,0,0]。我们只需要构造一个长度比 digits \\textitdigits digits多 111 的新数组,将首元素置为 111,其余元素置为 000 即可。
    • 算法

      • 只需要对数组 digits \\textitdigits digits进行一次逆序遍历,找出第一个不为 999 的元素,将其加一并将后续所有元素置零即可。如果 digits \\textitdigits digits中所有的元素均为 999,那么对应着「思路」部分的第三种情况,我们需要返回一个新的数组。

        class Solution:
            def plusOne(self, digits: List[int]) -> List[int]:
                n = len(digits)
                for i in range(n -1, -1, -1):
                    if digits[i] != 9:
                        digits[i] += 1
                        for j in range(i + 1, n):
                            digits[j] = 0
                        return digits
        
                return [1] + [0] * n
        

知识点查漏补缺

  • 在前面自己的解法那个代码里面

    • 放到vscode里面会有这个问题

      • 需要from typing import List
    • 那一步用append顺序会反 双边队列里面才有appendleft

    • python里面的/// 两种除法的区别

      • //是向下取整

0724 寻找数组的中心下标

AC

自己的解法

  • 一开始的错误代码

        - 一开始的代码
    class Solution:
        def pivotIndex(self, nums: List[int]) -> int:
            suml = 0 # 从左往右的和
            sumr = 0 # 从右往左的和
            # l = len(nums)
            lisl = []
            lisr = []
            for i in range(len(nums)):
                suml += nums[i]
                lisl.append(suml)
            for i in range(len(nums)-1,-1,-1):
                sumr += nums[i]
                lisr.append(sumr)   
            # flag = 0
            if lisl[0] == lisl[len(nums)-1]:
                return 0
            elif lisr[0] == lisr[len(nums)-1]:
                return len(nums)-1
            else:
                for j in range(len(nums)):
                    
                    if lisl[j] == lisr[j]:
                        return j
        
            return -1   
    

    lisl=[1,8,11,17,22,28]

    lisr=[6,11,17,20,21,28]

    返回5是不正确的,突然发现自己这个代码只适合中心点两边元素个数相等的情况…

    按照那个思路,在左和数组and 右和数组相同位置的话,那只能是元素个数相同了

  • 改了改,还是有问题

    class Solution:
        def pivotIndex(self, nums: List[int]) -> int:
            suml = 0 # 从左往右的和
            sumr = 0 # 从右往左的和
            # l = len(nums)
            lisl = []
            lisr = []
            for i in range(len(nums)):
                suml += nums[i]
                lisl.append(suml)
            for i in range(len(nums)-1,-1,-1):
                sumr += nums[i]
                lisr.append(sumr)   
            # flag = 0
            if lisl[0] == lisl[len(nums)-1]:
                return 0
            elif lisr[0] == lisr[len(nums)-1]:
                return len(nums)-1
            else:
                for j in range(len(nums)):
                    if lisl[j] == lisr[len(nums)-1-j]:
                        return j
    
        
            return -1   
    

    一开始感觉自己把两种特殊情况提出来很聪明,结果发现好像题目中这个条件的限制

    如果数组有多个中心下标,应该返回 最靠近左边 的那一个

    那么当左边的和为0的话,右边如果很多0,就会返回最右边的0

  • AC了

    • 总结一下自己的思路

      • 设立一个数组,每一位依次存储原数组nums从左到右的和
    • 再设立一个数组,每一位一次存储原数组nums从右到左的和

      • 然后由于题目要求返回靠左的中心点,那下标就从0到 len(nums)-1 从小到大遍历
    • 遇到相等的就返回j

  • 代码如下

    class Solution:
        def pivotIndex(self, nums: List[int]) -> int:
            suml = 0 # 从左往右的和
            sumr = 0 # 从右往左的和
            # l = len(nums)
            lisl = []
            lisr = []
            for i in range(len(nums)):
                suml += nums[i]
                lisl.append(suml)
            for i in range(len(nums)-1,-1,-1):
                sumr += nums[i]
    
            for j in range(len(nums)):
                    if lisl[j] == lisr[len(nums)-1-j]:
                        return j
    
        
            return -1   
    

    ​ 但时空复杂度大了些

其他做法

  • 官方题解:前缀和

    • 思路
      • 记数组的和为 t o t a l total total,当遍历到第 i i i个元素时,左侧元素之和为 s u m sum sum,那么右侧元素的和为 t o t a l − n u m s i − s u m total-nums_i-sum totalnumsisum,左右侧元素相等即为 s u m = t o t a l − n u m s i − s u m sum=total-nums_i-sum sum=totalnumsisum,即 2 × s u m + n u m s i = t o t a l 2\\times sum + nums_i=total 2×sum+numsi=total
      • 当中心索引左侧或右侧没有元素时,即为零个项相加,这在数学上称作「空和」( empty sum \\textempty sum empty sum)。在程序设计中我们约定「空和是零」
  • 题解没给python的,自己AC