继续算法的日常练习

字符串

最大公共前缀

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

编写一个函数来查找字符串数组的最大公共前缀;如果不存在,则返回 ""

def longestCommonPrefix(self, strs:List(str))->str:
        min_str = min(strs, key=len)
        result = ""
        p = 0
        while p < len(min_str):
            char = strs[0][p]
            for s in strs:
                if s[p] != char:
                    return result
            result += char
            p += 1
        return result

先纵向比对第一个字符,如果均为相同,则加入返回值中;若不正确,则直接返回

最长回文子串

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给你一个字串s找到s中最长的子串,并返回

class Solution(object):
    def longestPalindrome(self, s:str)->str:
        ans = ""
        for i in range(len(s)):
            temp = self.search(s,i,i)
            if len(temp) > len(ans):
                ans = temp
            temp = self.search(s,i,i+1)
            if len(temp) > len(ans):
                ans = temp
        return ans

    def search(self,s,first,end):
        while first>=0 and end<len(s) and s[first] == s[end]:
            first -= 1
            end += 1
        return s[first+1:end]

首先构造一个中心回文的函数 search,先为两边设置边界条件,然后当中心索引两边的值相等时,则向外拓展。我们构造这个辅助函数之后,在主函数中调用。(需要考虑奇偶回文的情况)

翻转字符串里的单词

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给你一个字符串s,反转字符串中单词的顺序

**注意:**输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

def reverseWords(self, s:str)->str:
    return (" ").join(s.split()[::-1])

啊,因为python丰富的内置函数,直接做完了。可以稍微讲下这几个函数的用法:

  • ("拼接符号").join(待拼接数组)
  • (待分隔数组).split(分隔符号)

双指针

指针常用的两种用法:

  • 首尾指针
  • 快慢指针

反转字符串

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题

def reverseString(self, s):
    i,j = 0,len(s)-1
    while i<j:
        s[i],s[j] = s[j],s[i]
        i += 1
        j -= 1
    return s

这里实际上是用了双指针的思想,相对移动然后互换位置。python中虽然没有指针,但是我们仍然可以通过数组去模拟这个过程,不过设置边界条件时一定要注意

数组拆分

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。返回该 最大总和

class Solution(object):
    def arrayPairSum(self, nums:List[int])->int:
        ans = 0
        nums = self.quick_sort(nums)
        print(nums)
        for i in range(len(nums)//2):
            ans += nums[i*2]
        return ans

    def quick_sort(self,array):
        if len(array) <= 1:
            return array
        else:
            reference = array[0]
            small = [s for s in array[1:] if s < reference]
            equal = [e for e in array if e == reference]
            large = [l for l in array[1:] if l > reference]
        return self.quick_sort(small) + equal + self.quick_sort(large)

这道题主要在于分析怎么得到最大总和,观察可以发现先对数组进行排序,再将已排序数组的偶数位累加即可。排序的话要尽量使用,较快的排序,不然会超时(冒泡就超了),所以这里使用快速排序

两数之和

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

def twoSum(self, numbers:List[int], target:int)->List[int]:
	i,j = 0,len(numbers)-1
	while True:
		a = numbers[i]+numbers[j]
		if a>target:
			j -= 1
		elif a<target:
			i += 1
		else:
			return [i+1,j+1]

对于这类题可以用一种匹配方式,有效的减少重复的索引:

  • 双指针指向首尾,求和与target进行比较
  • 当值较小时,我们将首指针前移
  • 当值较大时,我们将尾指针后移

移除元素

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。
  • nums 的其余元素和 nums 的大小并不重要。
  • 返回 k
	def removeElement(self, nums:List[int], val:int)->int:
        slow = 0
        for fast in range(len(nums)):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
        return slow

快慢指针,一个负责定位,一个负责向前索引匹配。这个思想十分常见

最大连续的1的个数

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给定一个二进制数组 nums , 计算其中最大连续 1 的个数

    def findMaxConsecutiveOnes(self, nums: List[int]) -> int:
        a,b = 0,0  # 分别存储当前最大连续数与历史最大连续数
        for i in range(len(nums)):
            if nums[i] == 0:
                if a > b:
                    b = a
                a = 0
            else:
                a += 1
        return max(a,b)

这里,我用了一个比较清晰的答案,同时这里也体现了快慢指针的思想,很优雅

长度最小的子数组

数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

    def minSubArrayLen(self, target:int, nums:List[int])->int:
        left,right = 0,0
        count = len(nums)+1
        sum = 0
        while right < len(nums):
            sum += nums[right]
            while sum >= target:
                count = min(count,right-left+1)
                sum -= nums[left]
                left += 1
            right += 1
        return 0 if count==len(nums)+1 else count

这里使用了尺缩法,其大致流程如下:

  • 右边界右移,直到和大于target,令左边界右移
  • 若和仍然大于target,左边界继续右移
  • 若和小于target,右边界右移

这种和上面的相对收缩有着异曲同工之妙,但是这里是追及收缩,要注意边界条件