数组算法练习题01

一、数组

(1)简单

1、原地删除排序数组中的重复项

给你一个 升序排列 的数组 nums ,请你原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

  • 定义两个指针(解决原地删除的问题),slow、fast;
    • 长度为n的数组,快指针fast从[1]遍历到[n-1]
    • 判断条件:if [fast] != [fast-1]
      • 则让slow += 1
class Solution(object):
    def removeDuplicates(self, nums):
        # nums = [0,0,1,1,1,2,2,3,3,4]
        n = len(nums)
        fast = slow = 1
        while fast<n:
            if nums[fast] != nums[fast - 1]:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow
2、原地移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

  • 使用双指针:
    • 长度为n的数组,从0地址开始遍历
    • 判断条件:if nums[fast] != val: 则
      • nums[slow] = nums[fast]
      • slow += 1
class Solution(object):
    def removeElement(self, nums, val):
        # nums =[0,1,2,2,3,0,4,2] val =2
        n = len(nums)
        slow = fast = 0
        while fast < n:
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow
3、两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

  • 暴力枚举:
    • 先选定i,再从除i外的所有元素找到相加为target的j;
      • 判断条件:if nums[i] + nums[j] == target:
class Solution(object):
    def twoSum(self, nums, target):
      n = len(nums)
      for i in range(n):
        for j in range(i+1, n):
          if nums[i] + nums[j] == target:
            return [i, j]
      return []
4、二分法查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

  • 使用二分法思想(时间复杂度是 O(log⁡n))
    • 先从数组的中位数开始查找;将中位数与target比较
    • 出现三种可能性
      • if nums[mid] == target:
      • if nums[mid] > target:
      • if nums[mid] < target:
class Solution(object):
    def search(self, nums, target):
        n = len(nums)
        left, right = 0, n-1
        while left <= right:
            # 使用(right - left)//2 + left作用:
            	# 例如:n=6,left=0, right=5
                # 5-2//2 = 1(会出现更新后的left小于现有的left)
                # 故 (right - left)//2 + left = 3
            mid = (right - left)//2 + left 
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            elif nums[mid] > target:
                right = mid - 1    
            else:
                mid = -1
        return -1
5、数组排序(.sort()函数的使用)

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

  • .sort()函数的使用
class Solution(object):
    def merge(self, nums1, m, nums2, n):
        nums1[m:] = nums2
        nums1.sort()
        return
6、数组中存在重复元素(set()函数的使用)

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

  • set()函数的使用
    • python的set()方法可以实现将对象去重,比较去重前后的对象长度即可
class Solution(object):
    def containsDuplicate(self, nums):
        return True if len(set(nums)) != len(nums) else False
7、杨辉三角

给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。在「杨辉三角」中,每个数是它左上方和右上方的数的和。

  • 杨辉三角

  • 分层计算:
    • 外层循环迭代每一行
    • 内层循环迭代每一行中元素数值
  • 最终将内层循环的结果添加到外层循环的每一行中
class Solution(object):
    def generate(self, numRows):
        ceng = 0
        yanghui = []
        while(ceng<numRows):
            i = 0   # 每层第i个元素
            hang = []
            while(i<=ceng):     # 每层元素数量不超过本层层数
                if (i==0 or i==ceng):   # 当元素i为每一层的头或尾时
                    hang.append(1)      # 头尾数值为1
                else:
                    hang.append(yanghui[ceng-1][i-1] + yanghui[ceng-1][i])
                i += 1  # 计算本层下一个元素
            yanghui.append(hang)
            ceng += 1   # 计算下一层
        return yanghui
8、一维数组动态和

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。请返回 nums 的动态和。

class Solution(object):
    def runningSum(self, nums):
        runningSum = []
        a = nums[0]
        for i in range(len(nums)):  
            if i!=0:    # 从第2个元素开始加法
                a += nums[i]
                runningSum.append(a)
            else:
                runningSum.append(nums[0])
        return runningSum
9、两数组交集(set()函数熟练运用)

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]

输出:[2]

  • 使用set()函数将现有数组进行简化
    • 对简化后的数组进行比较,并将比较的结果存放进新的数组
class Solution(object):
    def intersection(self, nums1, nums2):
        a = list(set(nums1))
        b = list(set(nums2))
        ans = []
        for i in range(len(a)):
            for j in range(len(b)):
                if a[i] == b[j]:
                    ans.append(b[j])
                else:
                    continue
        return ans
10、多数元素(.sort()函数)

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。

  • 使用.sort(),将原始的数组进行排序
    • 特殊情况:当数组中的多数元素出现次数小于n/2时,这个方法就失效了
class Solution(object):
    def majorityElement(self, nums):
        nums.sort()
        return nums[len(nums)//2]
11、搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。

输入: nums = [1,3,5,6], target = 5 输出: 2

  • 时间复杂度为 O(log n) 的算法:题目让我们使用二分法
    • 第一步:确定左右区间:left, right = 0, len(nums)
    • 第二部:进入循环并设置初始中间值mid
    • 第三部:是否忽略中间值mid的右侧数值
class Solution(object):
    def searchInsert(self, nums, target):
        left, right = 0, len(nums)  # 采用左闭右开区间[left,right)
        while left < right:         # 左闭右开所以不能有=,区间不存在
            mid = (right-left)//2 + left    # 防止溢出, //表示整除
            if nums[mid] >= target: 
                right = mid   # 若中点大于目标值,target在左侧,忽略右侧数值
            else:       # 中点小于目标值,target在右侧侧,忽略左侧数值
                left = mid + 1
        return left     # 最终left=right
12、移动数组中的0

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。

输入: nums = [0,1,0,3,2]

输出: [1,3,2,0,0]

  • 思路:
    • 使用两个指针,指针1指向要处理的元素;指针2指向与其对比的下一个元素
      • 检测到0调换容易出现调换前后都是0的情况,故使用检测到非0再调换
        • j
        • 0, 1, 0, 3, 2
        • i
        • 第一次循环nums[i]为0,则j+=1;变为
        • j
        • 0, 1, 0, 3, 2
        • i
        • 第二次循环,检测到非0,则调换nums[i], nums[j]
class Solution(object):
    def moveZeroes(self, nums):
        i = j = 0    # 使用两个指针
        while j < len(nums):
            if nums[j] != 0:
                nums[i], nums[j] = nums[j], nums[i]
                i += 1
            j += 1
        return 
13、加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:

输入:digits = [1,2,3]

输出:[1,2,4]

解释:输入数组表示数字 123。

  • 思路:
    • 从数组最后以为判断是否为9,这个特殊情况
      • 是:则将最后一位改为0;前一位+1
      • 否直接+1
    • 如果数组权威9;则在if外面返回:return [1] + [0]*n
  • 解题中出现的问题:
    • for i in range(n):
      • 这个循环会让i从0开始增加
      • 导致:
        • if digits[-i] == 9:
        • else:
          • digits[-i] = digits[-i] + 1出问题
      • 原因:-i = -0;指向了数组的第一个值而不是最后一个
class Solution(object):
    def plusOne(self, digits):
        n = len(digits)
        for i in range(1,n+1):		# 特别注意,i从1开始
            if digits[-i] == 9:     # 如果-i位为9
                digits[-i] = 0      # 设为0
            else:
                digits[-i] = digits[-i] + 1
                return digits	# 最终总有不为9的数值,所以在这里返回数值
        return [1] + digits  # 如果都是9,则在数组前加上1,并将数组内所有数改为0
14、最小花费爬楼梯(动态规划)

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。

示例 1:

输入:cost = [10,15,20]

输出:15

解释:你将从下标为 1 的台阶开始。

- 支付 15 ,向上爬两个台阶,到达楼梯顶部。

总花费为 15 。

  • 思路:要求是到达第n级台阶楼层顶部的最小花费,可以用动态规划来解,要求出状态转移方程。
  • 理解题意需要注意两点:
    • 第i级台阶是第i-1级台阶的阶梯顶部。
    • 踏上第i级台阶花费cost[i],直接迈一大步跨过而不踏上去则不用花费。

  • 到达第i级台阶的阶梯顶部的最小花费,有两个选择:
    • 从第i-1级台阶开始(上台阶走1步)
      • 先付出最小总花费zh[i-1]到达第i级台阶(即第i-1级台阶的阶梯顶部)
      • 踏上第i级台阶需要再花费cost[i],再迈一步到达第i级台阶的阶梯顶部,
      • 最小总花费为zh[i-1] + cost[i];
    • 从第i-2级台阶开始(上台阶走2步)
      • 先付出最小总花费zh[i-2]到达第i-1级台阶(即第i-2级台阶的阶梯顶部),
      • 从i-1级台阶直接到第i级台阶的阶梯顶部,需要花费cost[i-1]
      • 最小总花费为zh[i-2] + cost[i-1]);
  • 则minCost[i]是上面这两个最小总花费中的最小值。
    • zh[i] = min(zh[i-1] + cost[i], zh[i-2] + cost[i-1])
  • 假设从地面开始爬楼梯,用cost[-1]=0代表从地面开始的花费
  • 最小总花费的初始值为:
    • 第0级台阶: zh[0] = min(zh[-1]+cost[0], zh[-2]+cost[-1]) = min(0+cost[0], 0+cost[-1]) = min(cost[0], 0) = 0,
    • 第1级台阶: zh[1] = min(zh[0]+cost[1], zh[-1]+cost[0]) = min(cost[1], cost[0])。
    • 因为可以选择初始阶梯
      • 故:zh[0] = zh[1] = 0
class Solution(object):
    def minCostClimbingStairs(self, cost):
        n = len(cost)
        zh = [0]*n     # 共有n个阶梯,计算总花费要计算到n
        for i in range(1,n):    # 从第2个阶梯开始爬
            zh[i] = min(zh[i-1] + cost[i], zh[i-2] + cost[i-1])
        return zh[-1]
15、分饼干(贪心算法)

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例 1:

输入: g = [1,2,3], s = [1,1]

输出: 1

解释:

你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。

虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。

所以你应该输出1。

  • 思路:以 g = [10,9,8,7],s = [5,6,7,8] 为例。
    • 1、对 g 和 s 排序,目的就是为了从左到右遍历的时候,都是按照从小到大遍历。

    • 2、以第一个孩子为基准,找饼干

    • 3、找到饼干后将孩子(i)+1
class Solution(object):
    def findContentChildren(self, g, s):
        g.sort()
        s.sort()
        j = i = 0
        sum= 0
        for j in range(len(s)):
            if i<len(g) and g[i]<=s[j]:
                i+=1
                sum+=1
        return sum

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值