Leetcode学习之数组

数组

定义

数组是具有一定顺序关系的若干对象组成的集合,组成数组的对象称为数组元素

列如:

  • 向量对应一维数组
    A = [ a 0 a 1 . . . a n ] A = \begin{bmatrix} a_{0} & a_{1} & ... & a_{n} \end{bmatrix} A=[a0a1...an]

  • 矩阵对应二位数组

A m × n = [ a 00 a 01 . . . a 0 n − 1 a 10 a 11 . . . a 1 n − 1 . . . . . . . . . . . . a m − 10 a m − 11 . . . a m − 1 n − 1 ] A_{m\times n}=\begin{bmatrix} a_{00} & a_{01} & ... & a_{0n-1} \\ a_{10} & a_{11} & ... & a_{1n-1}\\ ... & ... & ... & ...\\ a_{m-10} & a_{m-11} & ... & a_{m-1n-1} \end{bmatrix} Am×n=a00a10...am10a01a11...am11............a0n1a1n1...am1n1

数组的储存

n维数组的定义

下标由n个数组成的数组称为n维数组

// 一维数组(线)
int [] a = new int[10];
// 二维数组(面)
int[ , ] = new int[2,3];
// 三维数组(体),类比书 页 行 列
int[ , , ] = new int[2,3,4]

数组存储的特点

  • 数组元素在内存中按顺序连续存储
  • C、C++、C#按行存储
  • 数组名表示该数组的首地址,是常量

常用数组的存储

一维数组a[n]

int [] a = new int[10]; 

占用字节数为
l o c ( a [ i ] ) = l o c ( a [ 0 ] ) + i × c loc(a[i])=loc(a[0])+ i\times c loc(a[i])=loc(a[0])+i×c

二维数组a[m,n]

列如:

int [ , ] a = new int[2,3];

占用字节数为
l o c ( a [ i , j ] ) = l o c ( a [ 0 , 0 ] ) + i × n × c + j × c = l o c ( a [ 0 , 0 ] ) + j × c × ( n + 1 ) loc(a[i,j])=loc(a[0,0]) + i \times n \times c + j \times c =loc(a[0,0]) + j \times c \times (n+1) loc(a[i,j])=loc(a[0,0])+i×n×c+j×c=loc(a[0,0])+j×c×(n+1)

三维数组a[m,n,l]

第一维下标变化最慢,第三维(最后一位)下标变化最快

列:

int[ , , ] a = new int[2,3,4]

占用字节数为
l o c ( a [ i , j , k ] ) = l o c ( a [ 0 , 0 , 0 ] ) + ( i × n × l + j × l + k ) × c loc(a[i,j,k]) = loc(a[0,0,0])+(i \times n \times l + j \times l + k) \times c loc(a[i,j,k])=loc(a[0,0,0])+(i×n×l+j×l+k)×c

练习

两数之和

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

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
输入:nums = [3,2,4], target = 6
输出:[1,2]
输入:nums = [3,3], target = 6
输出:[0,1]

解答

# 法1
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        for i in range(len(nums)):
            for j in range(i + 1,len(nums)):
                if nums[i] + nums[j] == target:
                    return [i, j]
# 法2
class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        numDict = dict()
        for i in range(len(nums)):
            if target-nums[i] in numDict:
                return numDict[target-nums[i]], i
            numDict[nums[i]] = i
        return [0]

最接近的三数之和

给你一个长度为 n 的整数数组nums和 一个目标值 target。请你从nums中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

输入:nums = [0,0,0], target = 1
输出:0

解法1:

# 三层循环,不推荐复杂度为O(n^3)
class Solution:
    def threeSumClosest(self, nums, target):
        error = abs(nums[0] + nums[1] + nums[2] - target)
        sum = 0
        for i in range(len(nums) - 2):
            for j in range(i + 1, len(nums) - 1):
                for k in range(j + 1, len(nums)):
                    sum = nums[i] + nums[j] + nums[k]
                    if abs(nums[i] + nums[j] + nums[k] - target) < error:
                        sum = nums[i] + nums[j] + nums[k]
                        error = abs(sum - target)

        return sum

解法二:

# 利用双指针的方法
class Solution:
    def threeSumClosest(self, nums: List[int], target: int) -> int:
        best = nums[0] + nums[1] + nums[2]
        def update(sum):
            nonlocal best
            if abs(sum - target) < abs(best - target):
                best = sum
        nums.sort()

        for i in range(len(nums)):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            left = i +1
            right = len(nums)-1
            while left < right:
                sum = nums[i] + nums[left] + nums[right]
                leftval = nums[left]
                rightval = nums[right]
                if sum == target:
                    return sum
                update(sum)
                if sum > target:
                    while left < right and rightval == nums[right]:
                        right-=1
                elif sum < target:
                    while left < right and leftval == nums[left]:
                        left +=1
        return best

解题思路:
本题目因为要计算三个数,如果靠暴力枚举的话时间复杂度会到O(n^3),需要降低时间复杂度
首先进行数组排序,时间复杂度 O(nlogn)O(nlogn)
在数组nums中,进行遍历,每遍历一个值利用其下标i,形成一个固定值 nums[i]
再使用前指针指向start = i + 1处,后指针指向end = nums.length - 1处,也就是结尾处
根据sum = nums[i] + nums[start] + nums[end]的结果,判断 sum 与目标 target 的距离,如果更近则更新结果ans
同时判断 sum与 target 的大小关系,因为数组有序,如果 sum > target 则 end–,如果 sum < target 则 start++,如果 sum == target 则说明距离为 0 直接返回结果
整个遍历过程,固定值为 n 次,双指针为 n 次,时间复杂度为O(n^2)O(n 2 )
总时间复杂度:O(nlogn) + O(n^2) = O(n^2)

作业题:删除有序数组中的重复项,移除元素,三数之和

移除元素

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

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。s

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        a =0
        b =0
        while a  < len(nums):
            if nums[a] !=val:
                nums[b] = nums[a]
                b +=  1 
            a+=1    
   		return b

三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

**注意:**答案中不可以包含重复的三元组。

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        # 存储结果列表
        res_list = []
        # 对nums列表进行排序,无返回值,排序直接改变nums顺序
        nums.sort()
        for i in range(len(nums)):
            # 如果排序后第一个数都大于0,则跳出循环,不可能有为0的三数之和
            if nums[i] > 0:
                break
            # 排序后相邻两数如果相等,则跳出当前循环继续下一次循环,相同的数只需要计算一次
            if i > 0 and nums[i] == nums[i-1]:
                continue
            # 记录i的下一个位置
            j = i + 1
            # 最后一个元素的位置
            k = len(nums) - 1
            while j < k:
                # 判断三数之和是否为0
                if nums[j] + nums[k] == -nums[i]:
                    # 把结果加入数组中
                    res_list.append([nums[i], nums[j], nums[k]])
                    # 判断j相邻元素是否相等,有的话跳过这个
                    while j < k and nums[j] == nums[j+1]: j += 1
                    # 判断后面k的相邻元素是否相等,是的话跳过
                    while j < k and nums[k] == nums[k-1]: k -= 1
                    # 没有相等则j+1,k-1,缩小范围
                    j += 1
                    k -= 1
                # 小于-nums[i]的话还能往后取
                elif nums[j] + nums[k] < -nums[i]:
                    j += 1
                else:
                    k -= 1
        return res_list


if __name__ == '__main__':
    s = Solution()
    result_list = s.threeSum([-1, 0, 1, 2, -1, -4])
    print(result_list)

删除有序数组中的重复项

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

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

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        left = 0
        right = 0
        while right < len(nums):
            if nums[right] == nums[left]:
                right = right +  1 
            else:
                left = left + 1 
                nums[left] = nums[right]
                
        return left + 1

因为空间复杂度为O(1),所以只能在原数组上进行修改。

首先暴力不考虑,我们需要做的是将数组分成左右两部分:

  1. 左侧是符合题意的结果;

  2. 右侧是等待选择的数组。

那么接下来我们要做的,就是在右侧选择与左侧最后一个不相等的加入到左侧最后。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值