首页 > 编程语言 >LeetCode题解:26.删除有序数组中的重复项【Python题解超详细,双指针法】,知识拓展:原地修改

LeetCode题解:26.删除有序数组中的重复项【Python题解超详细,双指针法】,知识拓展:原地修改

时间:2024-11-22 18:42:38浏览次数:3  
标签:26 nums Python 题解 元素 原地 修改 数组 id

题目描述

        给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

        考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[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(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # # 思路一:双指针法一
        # # 特殊情况的输出
        # if not nums:
        #     return 0
        # # 否则,使用双指针原地修改数组
        # n = len(nums)
        # fast = slow = 1
        # while fast < n:
        #     if nums[fast] != nums[fast - 1]:
        #         nums[slow] = nums[fast]
        #         slow += 1
        #     fast += 1
        # # slow就是数组中唯一值的数量
        # return slow

        # 双指针法二
        if not nums:
            return 0
        k=0
        for i in range(1,len(nums)):
            if nums[i]!=nums[k]:
                k+=1
                nums[k]=nums[i]
        return k+1

        双指针法主要思路(以方法二为例):通过两个指针(ki)在数组上进行遍历以原地去重:k 指向当前存放唯一元素的位置,i 用于遍历数组。如果当前遍历到的元素(nums[i])与上一个存储的唯一元素(nums[k])不同,就将其存储到数组的下一个位置(nums[k+1]),并移动指针 k。最终,k+1 即为数组中唯一元素的数量,同时数组的前 k+1 个位置包含了所有唯一元素。

知识拓展:原地修改

        或许有些小伙伴在面对题目要求统计唯一值数量时,会感到胸有成竹、信心满满,轻松联想到我们之前文章中详尽阐述过的 set 方法(具体可参见前文LeetCode题解:1.两数之和的知识拓展),进而写下以下代码:

# 获取nums中的唯一值,并将其再次转化为列表
nums=list(set(nums))
# 返回唯一值数量
return len(nums)

        但是等到提交的时候却发现这看似简洁、直接而又有效的代码却并未通过断言的测试,那么这是为什么呢?实际上,这道题目的重点并不在于统计唯一值的数量,而是如何原地修改数组,以获取唯一值的情况,那么什么是原地修改呢?使用set的解法为什么不满足条件呢?

        原地修改的概念

        所谓原地修改,指的是在对象的原内存位置上直接修改其内容,而不是创建一个新的对象。具体表现为:1)对象的 id() (内存地址)在操作前后保持不变;2)修改的是 对象的内部状态,而不是更换对象的引用。并且,在编程中,这种操作可以有效地减少内存使用和提高性能,是许多算法设计的重点要求。

        使用set函数的代码之所以出错,原因则在于题目明确要求原地修改数组,而这种方法创建了一个新的列表 list(set(nums)),直接替换了原数组 nums,不符合题目关于 原地操作 的要求。接着,我们再介绍下原地修改其它的相关知识。

        原地修改的操作

  1. 对列表的操作

    • list.sort():对列表进行排序,直接修改原列表。
    • list.append()list.extend():在原列表上添加元素。
    • list.pop()list.remove()del:直接修改原列表,移除元素。
    • 切片赋值:nums[:k] = [1, 2, 3],修改列表的一部分。
    • 索引赋值:nums[0] = 10,修改指定位置的值。
  2. 对字典的操作

    • dict[key] = value:直接修改字典内容。
    • dict.update():合并另一个字典的内容到原字典中。
  3. 对集合的操作

    • set.add()set.remove()set.discard():修改集合的内容。
    • set.update():将多个元素添加到集合。
  4. 对字符串(变更引用,非原地修改)

    • Python 中字符串是 不可变对象,任何操作都会创建新字符串对象。

        代码示例

# 列表的原地修改
nums = [3, 1, 4]
original_id = id(nums)
nums.sort()
print(id(nums) == original_id)  # True

# 字典的原地修改
data = {'a': 1, 'b': 2}
original_id = id(data)
data['c'] = 3
print(id(data) == original_id)  # True

# 字符串(非原地修改)
s = "hello"
original_id = id(s)
s = s.upper()  # upper() 创建了一个新字符串
print(id(s) == original_id)  # False

非原地修改的操作

        以下操作通常会创建新的对象,导致原地修改要求无法满足:

  1. copynums.copy() 创建了原列表的副本,新对象和原对象互不影响。

  2. set,set(nums) 会将列表转换为集合,创建一个全新的对象。

  3. sorted,sorted(nums) 返回一个新的排序列表,原数组不变。

  4. 切片创建新列表,nums[:]nums[1:] 会创建原数组的副本。

 如何检测是否原地修改

        可以通过 id() 函数来验证:

nums = [1, 2, 3]
original_id = id(nums)

# 原地修改
nums.sort()
print(id(nums) == original_id)  # True

# 非原地修改
nums = sorted(nums)
print(id(nums) == original_id)  # False

原地修改的意义

  • 减少空间开销:原地修改不会占用额外的内存空间,尤其对于大规模数据处理非常重要。
  • 提高性能:避免创建新的对象可以减少不必要的计算和复制操作。

 常见的原地修改场景

  1. 排序问题
    • 使用 list.sort() 而不是 sorted(),直接在原列表中进行排序。
  2. 去重问题
    • 使用双指针法在数组中删除重复项,直接修改原数组。
  3. 数据清洗
    • 在数据处理中,直接删除不需要的数据,而不是创建新副本。

感谢阅读,希望对你有所帮助~

标签:26,nums,Python,题解,元素,原地,修改,数组,id
From: https://blog.csdn.net/m0_74420622/article/details/143924910

相关文章

  • 【Python】基础语法速览(下)
    本文力图用最快的方式向大家陈列Python的基础语法,适合接触过其他编程语言后快速上手Python或供查阅巩固用参考书籍:《Python程序设计人工智能案例实践》[美]保罗·戴特尔哈维·戴特尔著码字不易,求点赞收藏加关注有问题欢迎评论区讨论目录Python基础语法速览(下)字......
  • python运行的话一定要运行完
    代码:importturtleastt.speed(0)t.color('red')d=0.1for_inrange(50):t.forward(d)t.left(360/6-1)d+=0.1t.color('blue')for_inrange(50):t.forward(d)t.left(360/6-1)d+=0.1t.color('green'......
  • Python怎么读取表头在中间行的CSV
    在Python中读取CSV文件时,如果表头(header)不在第一行而在中间某行,可以使用Pandas库来处理。Pandas是一个非常强大的数据处理库,可以方便地读取、处理和写入CSV文件。下面是一个详细的代码示例,展示如何读取表头在中间行的CSV文件。假设CSV文件名为example.csv,并且表头位于第3行(即索引......
  • android开发中,button设置shape后,shape的颜色不生效的问题解决方案
    检查AndroidManifest.xml中的主题的属性<applicationandroid:name=".BaseApplication"android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:networkSecurityConf......
  • python+pymysql(16)
    python操作mysql一、python操作数据库1、下载pymysql库,方法一:pip3installpymysql或pipinstallpymysql方法二:在pycharm中setting下载pymysql===============================2、打开虚拟机上的数据库===============================3、pymysql连接(1)连接......
  • [题解]P1641 生成字符串
    P1641[SCOI2010]生成字符串由题意可设\(f[i][j]\)表示用了\(i\)个\(0\),\(j\)个\(1\)的答案,那么有转移:\[f[i][j]=\begin{cases}0&i>j\\f[i][j-1]&i=j\\f[i-1][j]+f[i][j-1]&i<j\\\end{cases}\]状态数是\(O(n^2)\),转移是\(O(1)\),总时间复杂度\(O(n^2)\),期望得......
  • python 打包压缩文件
    1、自定义公共函数zip_files_and_dirsimportosimportzipfile#被压缩的目录,即使为空文件也要一起进行压缩,如果不为空则它的子级文件或目录也一起压缩,并且解压保持目录结构不变defzip_files_and_dirs(file_path_list,target_dir,target_file_name):#确保目标目录存......
  • python批量修改mysql中某个字段的长度
    突然被告知DB中某个关键字段长度要增大,涉及到N张表,改起来超麻烦,想着用代码改,比较少写这种增删表或者改变表结构的代码,记录下。importpymysqldefmodifyFieldVarcharLen(config,new_column_length):connection=pymysql.connect(**config)try:withconn......
  • [题解]P2151 [SDOI2009] HH去散步
    P2151[SDOI2009]HH去散步发现\(n,m\)非常小而\(t\)非常大,所以果断考虑矩阵。这道题如果不限制“不能立即沿刚刚过来的路回去”,就直接用邻接矩阵求\(t\)次幂然后直接调用\(ans[a][b]\)就好了。加上限制后,我们用点就比较难考虑了,因为点是无方向的。我们可以试着用边来转移,和点......
  • 超全!python中字符串拼接的各种姿势
    Python提供了多种字符串拼接的方式,每种方式在性能、可读性和灵活性上各有特点。以下是常见的字符串拼接方式及其总结:1.使用+操作符s1="Hello"s2="World"result=s1+""+s2#HelloWorld特点:简单易懂,适合小规模拼接。多个+拼接可能生成多个中间字符......