leetcode题解python版:26-30

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

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

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

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

为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

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

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

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

解:这道题读懂了示例就知道要做什么了,也就是说返回一个不重复元素的个数n,然后前n个数组的元素恰好是不重复元素的个数。这个问题用两个指针a和b就能解决,a记录不重复元素的最新位置,b记录索引位置。

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

执行用时:44 ms, 击败了88.94%的用户
内存消耗:14.8 MB

27、移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
解:和26题的要求相同,题目类似,可以按相同方法处理。

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

执行用时:36 ms, 中击败了88.09%的用户
内存消耗:13.7 MB,击败了23.30%的用户

28、实现 strStr()

实现 strStr() 函数。

给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。

说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

解:

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        n=len(needle)
        if not needle:
            return 0
        if len(haystack)<len(needle):
            return -1
        a=0
        b=n-1
        while b <len(haystack):    
            if haystack[a:b+1]==needle:
                return a
            else:
                a=a+1
                b=b+1
        return -1

执行用时:36 ms, 中击败了91.67%的用户
内存消耗:13.6 MB

29、两数相除

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。
返回被除数 dividend 除以除数 divisor 得到的商。
整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

解法一:总体来说就是一点点减除数,看要减几次。之所以要分那么多类是为了避免取绝对值时溢出(python不会有这个风险,但c会有,要时刻保持警惕)。

class Solution:
    def divide(self, dividend: int, divisor: int) -> int:
        if dividend==0:
            return 0
        if divisor==-1:
            if -dividend>=-2**31 and -dividend<=2**31-1:
                return -dividend
            elif -dividend<-2**31:
                return -2**31
            else:
                return 2**31-1
        if divisor==1:
            if dividend>=-2**31 and dividend<=2**31-1:
                return dividend
            elif dividend<-2**31:
                return -2**31
            else:
                return 2**31-1
        result=0
        if (dividend<0 and divisor>0):
            while dividend<0:
                dividend=dividend+divisor
                result=result+1
            if dividend>0:
                result=result-1
            result=-result
        elif(dividend>0 and divisor<0): 
            while dividend>0:
                dividend=dividend+divisor
                result=result+1
            if dividend<0:
                result=result-1
            result=-result
        elif (dividend>0 and divisor>0):
            while dividend>0:
                dividend=dividend-divisor
                result=result+1
            if dividend<0:
                result=result-1
        else:
            while dividend<0:
                dividend=dividend-divisor
                result=result+1
            if dividend>0:
                result=result-1
        if result>2**31-1:
            return 2**31-1
        elif result<-2**31:
            return -2**31
        else:
            return result

该算法在算特别大的数时会超时,因此需要加速算法。

解法二:
每次可以把除数扩大二倍,确定被除数在哪个大致区间,然后不断缩小范围,这有点类似于求一个数的二进制。
编程序时需要特殊注意等于号是否需要加

class Solution:
    def divide(self, dividend: int, divisor: int) -> int:
        if dividend==0:
            return 0
        if divisor==-1:
            if -dividend>=-2**31 and -dividend<=2**31-1:
                return -dividend
            elif -dividend<-2**31:
                return -2**31
            else:
                return 2**31-1
        if divisor==1:
            if dividend>=-2**31 and dividend<=2**31-1:
                return dividend
            elif dividend<-2**31:
                return -2**31
            else:
                return 2**31-1
        result=0
        if (dividend<0 and divisor>0) or (dividend>0 and divisor<0):
            sgn=-1
        else:
            sgn=1 
        dividend=abs(dividend)
        divisor=abs(divisor)
        t=divisor
        if t>dividend:
            return 0
        if t==dividend:
            return 1
        a=[0]
        b=[0]
        s=1
        while dividend>=t:
            a.append(t)
            t=t+t
            b.append(s)
            s=s+s
        k=len(a)
        for i in range(k-1,0,-1):
            if dividend>=a[i]:
                dividend=dividend-a[i]
                result=result+b[i]
        result=sgn*result
        if result>2**31-1:
            return 2**31-1
        elif result<-2**31:
            return -2**31
        else:
            return result

执行用时:44 ms, 击败了73.16%的用户
内存消耗:13.7 MB

30、串联所有单词的子串

给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。

注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
注:重复单词要各用一次

输入:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
输出:[]

解法一:遍历法

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        if not words:
            return []
        if not s:
            return []
        n=len(words[0])
        a=0
        ans=[]
        while a+len(words)*n-1<len(s):
            clist=words.copy()
            find=True
            for i in range(len(words)):
                if s[a+i*n:a+i*n+n] in clist:
                    clist.remove(s[a+i*n:a+i*n+n])
                else:
                    find=False
                if find==False:
                    break
            if find==True:
                ans.append(a)
            a=a+1
        return ans

执行用时:1948 ms, 击败了14.90%的用户
内存消耗:13.9 MB, 击败了51.35%的用户

解法二:双指针移动
跟遍历法相比,该方法的巧妙之处在于它是固定了起始点i(0,1,…len(words)),然后每次移动len(words)距离。这样可以借用之前一步的部分信息,从而提高程序效率。而+1的遍历每一步都需要重复判断,但本方法不需要。

class Solution:
    def findSubstring(self, s: str, words: List[str]) -> List[int]:
        if not words:
            return []
        if not s:
            return []
        adict={}
        ans=[]
        for i in words:#计数
            if i in adict:
                adict[i]=adict[i]+1
            else:
                adict[i]=1
        n=len(words[0])
        for i in range(n):
            left=right=i
            currentdict={}
            count=0
            for j in range(len(words)):
                currentString=s[right:right+n]
                if currentString in adict and currentString in currentdict:
                    currentdict[currentString]+=1
                    count=count+1
                elif currentString in adict:
                    currentdict[currentString]=1
                    count=count+1
                right=right+n
            while True:
                if count==len(words) and currentdict==adict:
                    ans.append(left)
                if right+n>len(s):
                    break 
                s1=s[left:left+n]
                if s1 in currentdict:
                    currentdict[s1]-=1
                    count=count-1
                left=left+n
                s2=s[right:right+n]
                if s2 in adict and s2 in currentdict:
                    currentdict[s2]+=1
                    count=count+1
                elif s2 in adict:
                    currentdict[s2]=1
                    count=count+1
                right=right+n
        return ans                 

执行用时:84 ms, 击败了87.73%的用户
内存消耗:13.8 MB, 击败了64.86%的用户

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值