LeetCode初级算法练习——数组篇

数组篇

26从排序数组中删除重复项

给定一个有序数组,你需要原地删除其中的重复内容,使每个元素只出现一次,并返回新的长度。

不要另外定义一个数组,您必须通过用 O(1) 额外内存原地修改输入的数组来做到这一点。

示例:

给定数组: nums = [1,1,2],

你的函数应该返回新长度 2, 并且原数组nums的前两个元素必须是1和2
不需要理会新的数组长度后面的元素

Given a sorted array, remove the duplicates in-place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

Example:

Given nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the new length.
class Solution:
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        前提是已排序
        判断nums[j]与nums[i-1]元素,相等j+1继续判断下一元素;不相等,nums[j]赋值给nums[i],
        返回i与size的最小值(size为0时返回size,没有不相同的时候           size==i,有相同的i

122.买卖股票的最佳时机 II—— best time to buy and shell stock II 

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

    设计一个算法来找到最大的利润。你可以完成尽可能多的交易(多次买卖股票)。然而,你不能同时参与多个交易(你必须在再次购买前出售股票)。

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).


class Solution:
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        total = 0
        #当len(prices)==0时,不进行for循环,直接ruturn total
        for i in range(1,len(prices)):
            total += max(0,prices[i]-prices[i-1])
        return total

189旋转数组rotate array

将包含 n 个元素的数组向右旋转 步。

例如,如果  n = 7 ,  k = 3,给定数组  [1,2,3,4,5,6,7]  ,向右旋转后的结果为 [5,6,7,1,2,3,4]

class Solution:
    def rotate(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        if k%len(nums)!=0:#整除则旋转一轮不变
            l=len(nums)
            k=k%l#取余知旋转几次
            nums[:k],nums[k:]=nums[l-k:],nums[:l-k]

217存在重复

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

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

class Solution:
    def containsDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """      
        #>>> s = set([1, 1, 2, 2, 3, 3])  
        #>>> s  
        #{1, 2, 3}  在se()中没有重复的key
        return len(nums) != len(set(nums))
"""利用hash table,别忘了判断空数组的情况.其实更麻烦"""
class Solution(object):
    def containsDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        if not nums:
            return False
        dic = dict() #用list(),append添加会超时
        for num in nums:
            if num in dic:
                return True
            dic[num] = 1
        return False

136只出现一次的数字

给定一个整数数组,除了某个元素外其余元素均出现两次。请找出这个只出现一次的元素。 

备注:

你的算法应该是一个线性时间复杂度。 你可以不用额外空间来实现它吗?

class Solution:
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        #由于整数数组只有一个元素出现一次,利用异或(两个相同的数的异或为0)运算所有数组元素
        #出现两次的元素不管顺序如何最后都会异或为0,最后只会剩下出现一次的某元素     
        a = 0
        for i in nums:
            a ^= i
        return a

350两个数组的交集 II

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

例如:
给定 nums1 = [1, 2, 2, 1]nums2 = [2, 2], 返回 [2, 2].

注意:

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

跟进:

  • 如果给定的数组已经排好序呢?你将如何优化你的算法?
  • 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
  • 如果nums2的元素存储在磁盘上,内存是有限的,你不能一次加载所有的元素到内存中,你该怎么办?
class Solution:
    def intersect(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        #遍历nums1,用字典对应元素及出现次数
        dic = dict()
        for num in nums1:
            if num in dic:
                dic[num] += 1
            else:
                dic[num] = 1
        #遍历nums2,判断是否在字典中,存在value-1,并加入到list中
        n = list()
        for num in nums2:
            if num in dic.keys() and dic[num] != 0:
                    dic[num] -= 1
                    n.append(num)
        return n
"""但是python内置了Counter类型数组,可以方便实现计数功能"""
class Solution(object):
    def intersect(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        from collections import Counter
        c1 = Counter(nums1)
        c2 = Counter(nums2)
        return list((c1&c2).elements())

66加一

给定一个非负整数组成的非空数组,在该数的基础上加一,返回一个新的数组。

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

可以假设整数不包含任何前导零,除了数字0本身。

示例 1:

输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。

示例 2:

输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321。


class Solution:
    def plusOne(self, digits):
        """
        :type digits: List[int]
        :rtype: List[int]
        """
        #str和int的相互转换
        sum = 0
        for i in digits:
            sum = sum * 10 + i
        return [int(x) for x in str(sum+1)]


class Solution:
    def plusOne(self, digits):
        """
        :type digits: List[int]
        :rtype: List[int]
        """
        n = len(digits) 
        i = n-1
        while i > -1:#从列表末尾开始加1计算,并判断是否进位,循环至最高位
            if digits[i] != 9:#第i个元素不为9,元素直接+1,并返回列表,首轮判定的是列表末尾元素
                digits[i] = digits[i] + 1
                return digits
            elif i > 0: #如果为9,且不是最高位元素,该位元素=0,i-1(上一位元素要进位加1,重新判断i-1位的元素是否为9)
                digits[i] = 0
                i = i - 1
                continue
            else:#如果为9,且i=0(此时为最高位,如999+1=1000,第0位元素=0,在列表首位添加数字元素1)
                digits[i] = 0
                digits =[1] + digits
            i = i - 1#跳出循环条件
        return digits

283移动零

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

例如, 定义 nums = [0, 1, 0, 3, 12],调用函数之后, nums 应为 [1, 3, 12, 0, 0]

注意事项:

  1. 必须在原数组上操作,不要为一个新数组分配额外空间。
  2. 尽量减少操作总数。
class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        m = len(nums)
        i = 0
        while i
1 两数之和

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例:

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

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        dic = dict()
        for index,value in enumerate(nums):
            sub = target - value
            if sub in dic:
                return [dic[sub],index]
            else:
                dic[value] = index

36有效的数独

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

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

上图是一个部分填充的有效的数独。

数独部分空格内已填入了数字,空白格用 '.' 表示。

示例 1:

输入:
[
  ["5","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
输出: true

示例 2:

输入:
[
  ["8","3",".",".","7",".",".",".","."],
  ["6",".",".","1","9","5",".",".","."],
  [".","9","8",".",".",".",".","6","."],
  ["8",".",".",".","6",".",".",".","3"],
  ["4",".",".","8",".","3",".",".","1"],
  ["7",".",".",".","2",".",".",".","6"],
  [".","6",".",".",".",".","2","8","."],
  [".",".",".","4","1","9",".",".","5"],
  [".",".",".",".","8",".",".","7","9"]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
     但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

说明:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 给定数独序列只包含数字 1-9 和字符 '.' 。
  • 给定数独永远是 9x9 形式的。
class Solution:  
    # @param board, a 9x9 2D array  
    # @return a boolean  
    def valid(self,x,y,tmp,board): 
        #tem元素位于x行,y列
        for i in range(9):  #判断第y列元素是否有等于tmp元素的
            if board[i][y]==tmp:  
                return False  
        for j in range(9):  #判断第x行元素是否有等于tmp元素的
            if board[x][j]==tmp:  
                return False  
        for i in range(3):  #判断3*3宫内是否有等于tmp元素的
            for j in range(3):  
                if board[(x//3)*3+i][(y//3)*3+j]==tmp:  #根据x,y计算出3*3宫的元素下标范围,x//3得到的是整数部分
                    return False  
        return True  
    def isValidSudoku(self, board):  
        for i in range(9):  #遍历 行
            for j in range(9): #在行不变的情况下,遍历一整列 
                if board[i][j]=='.':   #在为时'.',继续遍历
                    continue  
                tmp=board[i][j]  #当为数字时,赋值给tmp
                board[i][j]='D'  #将该位元素修改为不相关元素
                if self.valid(i,j,tmp,board)==False:  #判断tmp与数组所有元素(包括board[i][j],所以修改了board[i][j])是否相同
                    return False  
                else:  #不相同则将board[i][j]修改回来
                    board[i][j]=tmp  
        return True  
class Solution:
    def isValidSudoku(self, board):
        """
        :type board: List[List[str]]
        :rtype: bool
        """
        return (self.is_row_valid(board) and
            self.is_col_valid(board) and
            self.is_square_valid(board))

    def is_row_valid(self, board):
        for row in board:#遍历每一行
            if not self.is_unit_valid(row): #is_unit_valid(row)返回的是False,说明行中有相同元素,则return False
                return False
        return True

    '''
    zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

    如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
    >>>a = [1,2,3]
    >>> b = [4,5,6]
    >>> c = [4,5,6,7,8]
    >>> zipped = zip(a,b)     # 打包为元组的列表
    [(1, 4), (2, 5), (3, 6)]
    >>> zip(a,c)              # 元素个数与最短的列表一致
    [(1, 4), (2, 5), (3, 6)]
    >>> zip(*zipped)          # 与 zip 相反,可理解为解压,返回二维矩阵式
    [(1, 2, 3), (4, 5, 6)]
    '''
    def is_col_valid(self, board):
        for col in zip(*board):#zip(*board)将board中对应列的元素以列表形式打包成一个个元祖
            if not self.is_unit_valid(col):#判断是否有相同元素
                return False
        return True

    def is_square_valid(self, board):
        for i in (0, 3, 6):
            for j in (0, 3, 6):
                square = [board[x][y] for x in range(i, i + 3) for y in range(j, j + 3)] #将3*3宫的元素以列表形式存储在square中
                if not self.is_unit_valid(square):
                    return False
        return True

    def is_unit_valid(self, unit):
        unit = [i for i in unit if i != '.'] #遍历参数unit将不为.的元素以列表形式存储到变量unit
        return len(set(unit)) == len(unit) #利用set的性质,如果有重复元素则两边不相等,返回False
48 旋转图像

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

将图像顺时针旋转 90 度。

说明:

你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。

示例 1:

给定 matrix = 
[
  [1,2,3],
  [4,5,6],
  [7,8,9]
],

原地旋转输入矩阵,使其变为:
[
  [7,4,1],
  [8,5,2],
  [9,6,3]
]

示例 2:

给定 matrix =
[
  [ 5, 1, 9,11],
  [ 2, 4, 8,10],
  [13, 3, 6, 7],
  [15,14,12,16]
], 

原地旋转输入矩阵,使其变为:
[
  [15,13, 2, 5],
  [14, 3, 4, 1],
  [12, 6, 8, 9],
  [16, 7,10,11]
]

class Solution:
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: void Do not return anything, modify matrix in-place instead.
        """
        """使用两次旋转
        The idea was firstly transpose the matrix and then flip it symmetrically. For instance,
        1  2  3             
        4  5  6
        7  8  9
        after transpose, it will be swap(matrix[i][j], matrix[j][i])
        1  4  7
        2  5  8
        3  6  9
        Then flip the matrix horizontally. (swap(matrix[i][j], matrix[i][matrix.length-1-j])
        7  4  1
        8  5  2
        9  6  3
        """
        n = len(matrix)
        #对角线元素交换
        for i in range(n):
            for j in range(i):
                matrix[i][j],matrix[j][i] = matrix[j][i],matrix[i][j]
        #同一行前后对应位置的元素互换
        left = 0
        right = n - 1
        while left < right:
            for i in range(n):
                matrix[i][left],matrix[i][right] = matrix[i][right],matrix[i][left]
            left = left + 1
            right = right - 1






你可能感兴趣的:(LeetCode算法)