美文网首页
Leetcode 数组(简单)

Leetcode 数组(简单)

作者: 大豆油 | 来源:发表于2019-10-22 22:02 被阅读0次

一、数组题目(简单)

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

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

解题思路:
运用双指针,快指针进行遍历,慢指针与快指针对比,遇到不一样的,则慢指针加1,快指针的值赋值给慢指针更新后的位置,代码如下:

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        
        i = 0
        for v in nums:
            if nums[i] != v:
                i += 1
                nums[i] = v
                
        # and中含0,则返回0;都非0,则返回后一个值
        return len(nums) and i+1

注意点:

  1. 注意考虑数组为空的情况
  2. 原地处理,数组的大小不变,只取前几位不重复的数据,所以需要进行 and 操作。

122. 买卖股票的最佳时机 II

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

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

解题思路:
只需要关注后一天比前一天多就行了。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        
        if len(prices) == 0:
            return 0
        profit = 0
        for i in range(len(prices)-1):
            if prices[i] < prices[i+1]:
                profit += (prices[i+1]-prices[i])
            i +=1
            
        return profit

注意点:

  1. 注意考虑数组为空的情况。

旋转数组

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

  • 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
  • 要求使用空间复杂度为 O(1) 的 原地 算法。

解题思路:

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        ## 1. 时间复杂度较高为O(Kn),时间超时
        # size = len(nums)
        # for i in range(k):
        #     temp = nums[size-1]
        #     for j in range(size-1):
        #         nums[size-1-j] = nums[size-2-j]
        #     nums[0] = temp
        
        
        ### 2. 重新组合
        # k=k%len(nums)#保证循环次数在0-len(nums)之间
        # nums[:]=nums[len(nums)-k:]+nums[:len(nums)-k]#切割成两块重新组合
           
            
        ### 3. 使用 reversed() 倒序处理
        length = len(nums)
        k = k%length
        nums.reverse()
        nums[0:k] = reversed(nums[0:k])
        nums[k:] = reversed(nums[k:])

217. 存在重复元素

给定一个整数数组,判断是否存在重复元素。

如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

解题思路:

class Solution:
    def containsDuplicate(self, nums: List[int]) -> bool:
        
        ## 1. 集合法
        # return len((set(nums))) != len(nums)
    
        ## 2.排序法
#         nums.sort()
           # 这里的遍历没有最后一位,因此不需要担心 i+1 会越位
#         for i in range(len(nums)-1):
#             if nums[i] == nums[i+1]:
#                 return True
        
#         return False
    
        
        ## 3.hash表法
        dic = {}
        for num in nums:
            if dic.get(num):
                return True
            dic[num] = 1
        
        return False

136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

解题思路:

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        
        ## 1. 排序法
#         nums.sort()
#         for i in range(0, len(nums)-1, 2):
#             if nums[i] != nums[i+1]:
#                 return nums[i]
        
#         return nums[-1]
    
        ## 2. 位运算
        # 异或运算,只要两个相同的数进行异或运算,结果为0;
        # 结合律(即(a^b)^c == a^(b^c))
        # 交换律 a ^ b = b ^ a
        # 对于任何数x,都有x^x=0,x^0=x
        # 自反性 A XOR B XOR B = A xor 0 = A
        # 那么把这个数组所有数做异或运算,通过交换律和结合律,相同的数抵消,生下来的就是那个不同的数
        # 比如:数组为[a, b, c, a, b]
        # a^b^c^a^b = a^a^b^b^c = (a^a)^(b^b)^c = 0 ^ 0 ^ c = (0 ^ 0) ^ c = 0 ^ c = c

        # sum = 0
        # for i in nums:
        #     sum = sum^i
        # return sum
        
        ## 3.list的弹出与删除
        while len(nums) != 1:
            lastCha = nums.pop()
            if lastCha in nums:
                nums.remove(lastCha)
            else:
                return lastCha
            
        return nums[0]

350. 两个数组的交集 II

给定两个数组,编写一个函数来计算它们的交集。

示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]

示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]

说明:

  • 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
  • 我们可以不考虑输出结果的顺序。

进阶:

  • 如果给定的数组已经排好序呢?你将如何优化你的算法?
  • 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
  • 如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

解题思路:

from collections import *

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:

        # 普通解法1
#         result = []
#         for i in nums1:
#             if i in nums2:
#                 result.append(i)
#                 # remove 删除的是第一个与value值相等的数
#                 nums2.remove(i)
        
#         return result

        # 普通解法2
        # Counter 是用来进行计数的工具
        # return list((Counter(nums1) & Counter(nums2)).elements())
        
        # 进阶解法1:
        nums1.sort()
        nums2.sort()
        i=j=0
        result = []
        while i<len(nums1) and j<len(nums2):
            if nums1[i]==nums2[j]:
                result.append(nums1[i])
                i += 1
                j += 1
            elif nums1[i] < nums2[j]:
                i += 1
            else:
                j += 1
        
        return result 

注意点:

  1. Counter 的使用

66. 加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

解题思路:

class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:

        # 解法1:先把数组转换成数字+1,然后在转换成数组
#         num = 0
#         i = 1
#         for d in digits[::-1]:
#             temp = d * i
#             i = i * 10
#             num += temp
        
#         num += 1
         
#         return map(int,str(num))

        # 解法2:思路一样,只是数组转换成数字的过程使用字符串
        return map(int, str(int(''.join('%s' % i for i in digits))+1))

注意点:

  1. 主要是数组转换成数字,使用字符串更快。
  2. map 的使用更快。

283. 移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

解题思路:

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        # 双指针法,遇到0就与后面的快指针换
        i = 0
        for index, num in enumerate(nums):
            
            if num == 0:
                continue
            
            if nums[i] == 0:
                nums[i], nums[index] = nums[index], nums[i]
            
            i += 1

        # 遍历,遇到0删除,再在末尾补0
        # for i in nums[:]:
        #     if i==0:
        #         nums.append(0)
        #         nums.remove(0)

注意点:

  1. 数组内部的互换位置,不需要用temp做中间变量。

1. 两数之和

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

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

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

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

解题思路:

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        
        # 解法1:双重遍历
#         for i, inum in enumerate(nums):
#             for j, jnum in enumerate(nums[i+1:]):
                
#                 if (inum + jnum) == target:
#                     return [i,i+j+1]
                
        # 解法2:hash 解法
        hashmap={}
        for ind,num in enumerate(nums):
            hashmap[num] = ind
        for i,num in enumerate(nums):
            j = hashmap.get(target - num)
            if j is not None and i!=j:
                return [i,j]

注意点:

  1. dict 的使用。

36. 有效的数独

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

解题思路:

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        # 思路三: 思路二的另一种实现方式。代码更为简洁(借鉴)
        Cell = [[] for i in range(9)]                   # 没有必要用dict,我们只某个数字关心有没有出现过
        Col =  [[] for i in range(9)]
        Row =  [[] for i in range(9)]
        
        for i,row in enumerate(board):                  # 将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中
            for j,num in enumerate(row):
                if num != '.':
                    k = (i//3)*3 + j//3                   # 利用地板除,向下取余。巧妙地将矩阵划分为九块
                    if num in Row[i] + Col[j] + Cell[k]:    # list的骚操作,将三个list顺序的拼接 
                        return False
                    Row[i].append(num)
                    Col[j].append(num)
                    Cell[k].append(num)
                        
        return True

注意点:

  1. 二维数组的表示。
  2. 字典的使用可有效的检查重复。

48. 旋转图像

给定一个 n × n 的二维矩阵表示一个图像。

将图像顺时针旋转 90 度。

解题思路:

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        
        n = len(matrix)
        
        '''矩阵转置'''
        for x in range(n):
            for y in range(x):
                matrix[x][y], matrix[y][x] = matrix[y][x], matrix[x][y]
        
        '''转置后列变换'''
        # for i in range(len(matrix)):
        #     for j in range(len(matrix[i])//2):
        #         matrix[i][j],matrix[i][len(matrix)-1-j] = matrix[i][len(matrix)-1-j], matrix[i][j]
        for i in range(n):
            matrix[i] = matrix[i][::-1]

注意点:

  1. 二维数组的旋转可以用转置和行列变换解决。

二、总结

使用方法总结:

  1. 双指针法,主要针对删除数组中的重复项。
  2. reversed() 方法,主要用于旋转数组,还有对于数组的重新组合。
  3. hash 方法,是否存在重复项。
  4. 数组转数字,数字转数组,使用字符串更快。

注意点总结:

  1. 考虑数组为空的情况。
  2. Counter 的使用。
  3. map 的使用,数组转数字和数字转数组,用字符串更快。
  4. 数组内部互换位置,不需要 temp。

相关文章

网友评论

      本文标题:Leetcode 数组(简单)

      本文链接:https://www.haomeiwen.com/subject/zijipctx.html