167.两数之和(简单)
题目描述:在有序数组中找出两个数,使它们的和为 target。
思路:
使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
如果两个指针指向元素的和 sum == target,那么得到要求的结果;
如果 sum > target,移动较大的元素,使 sum 变小一些;
如果 sum < target,移动较小的元素,使 sum 变大一些。
数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
i = 1
j = len(numbers)
while i < j:
sum = numbers[i-1] + numbers[j-1]
if sum > target:
j = j - 1
elif sum < target:
i = i + 1
else:
return [i, j]
return []
633.两数平方和(简单)
题目描述:判断一个非负整数是否为两个整数的平方和。
思路:
对于给定的非负整数c, 需要判断是否存在整数a和b,使得 。可以枚举a和b所有的情况,时间复杂度为,但是暴力的枚举法实在没必要,因此我们可以用双指针法来解决。
因为最多只需要遍历一次 0~sqrt(target),所以时间复杂度为 O又因为只使用了两个额外的变量,因此空间复杂度为 O(1)。
class Solution:
def judgeSquareSum(self, c: int) -> bool:
a = 0
b = int(sqrt(c))
while a <= b:
sum = a*a + b*b
if sum > c:
b = b - 1
elif sum < c:
a = a + 1
else:
return True
return False
345.反转元音字符(简单)
给你一个字符串
s,仅反转字符串中的所有元音字母,并返回结果字符串。 元音字母包括'a'、'e'、'i'、'o'、'u',且可能以大小写两种形式出现。
使用双指针,一个指针从头向尾遍历,一个指针从尾到头遍历,当两个指针都遍历到元音字符时,交换这两个元音字符。
时间复杂度为 O(N):只需要遍历所有元素一次
空间复杂度 O(1):只需要使用两个额外变量
class Solution:
def reverseVowels(self, s: str) -> str:
vowel = "aeiouAEIOU"
ls = str(list(s))
a, b = 0, len(s)-1
while a < b:
if s[a] not in vowel:
a = a + 1
elif s[b] not in vowel:
b = b - 1
else:
ls[a], ls[b] = ls[b], ls[a]
a = a + 1
b = b - 1
return ''.join(ls)
125.验证回文串(简单)
给定一个字符串,验证其是否是回文串,只考虑字母和数字字符,可以考虑字母的大小写。 本题中,我们将空字符串定义为有效的字符串。
思路: 所谓的回文字符串,是指具有左右对称特点的字符串,例如 "abcba" 就是一个回文字符串。 使用双指针可以很容易判断一个字符串是否是回文字符串:
- 设i和j两个指针,一个指向首元素,一个指向尾元素。
- 遍历字符串,当i和j指针指向字符都为字母或数字时进行比较,若比较结果为false,直接返回false,结束程序,否则继续遍历。
- 当i>=j时,此时说明字符串遍历并比较完毕,直接返回true就行。
class Solution:
def isPalindrome(self, s: str) -> bool:
if len(s) == 1:
return True
start, end = 0, len(s) - 1
while start < end:
while not s[start].isalnum():
if start == end:
break
start = start + 1
while not s[end].isalnum():
if start == end:
break
end = end - 1
if s[start].upper() != s[end].upper():
return False
start = start + 1
end = end - 1
return True
# 优化后:
class Solution:
def isPalindrome(self, s: str) -> bool:
sgood = "".join(i) for i in s if isalnum())
n = len(sgood)
start, end = 0, n-1
while start < end:
if sgood[start].lower != sgood[end].lower:
return False
start, end = start + 1, end - 1
return True
680.验证回文字符串2(简单)
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
思路: 同 125.验证回文串
本题的关键是处理删除一个字符。在使用双指针遍历字符串时,如果出现两个指针指向的字符不相等的情况,我们就试着删除一个字符,再判断删除完之后的字符串是否是回文字符串。
在判断是否为回文字符串时,我们不需要判断整个字符串,因为左指针左边和右指针右边的字符之前已经判断过具有对称性质,所以只需要判断中间的子字符串即可。
在试着删除字符时,我们既可以删除左指针指向的字符,也可以删除右指针指向的字符。
class Solution:
def validPalindrome(self, s: str) -> bool:
if len(s) <= 2:
return True
start, end = 0, len(s) - 1
def isPalindrome(start, end):
while start < end:
if s[start] != s[end]:
return False
start += 1
end -= 1
return True
while start < end:
if s[start] == s[end]:
start += 1
end -= 1
else:
return isPalindrome(start+1, end) or isPalindrome(start, end-1)
return True
344.反转字符串(简单)
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 说明: 本题中,我们将空字符串定义为有效的回文串。
- 定义左右指针,左指针指向字符串头, 右指针指向字符串尾;
- 当左指针所指的下标小于右指针所指的下标时,进入循环, 否则结束循环
- 交换左右指针指向的元素之后,左指针加1,右指针减1, 继续步骤1,2, 直至交换完成
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
if not s: # 考虑s为空字符串的情况
return []
start, end = 0, len(s)-1
while start < end:
s[start], s[end] = s[end], s[start]
start += 1
end -= 1
return s
11题, 盛最多水的容器(简单)
左右指针分别确定左右边界,两个指针都向中间移动
此时形成的最大面积为 min(height[left], height[right]) * (right - left);
即两个边界的较小值 与 边界间距离 的乘积;
这时遇到问题,需要移动左指针还是右指针呢?一旦移动指针,意味着上一个指针确定的边界被丢弃,首先我们知道 此时区域的最大面积为 两个边界的较小值 与 边界间距离 的乘积;
随着指针的移动,边界间的距离必然减小,想要使围成的区域面积变大,我们需要通过移动边界值较小的指针,来使面 积往可能增大的方向转变。
class Solution:
def maxArea(self, height: List[int]) -> int:
if len(height) < 2:
return 0
start, end = 0, len(height) - 1
current_maxArea = 0
while start < end:
min_start_end = min(height[start], height[end])
if height[start] < height[end]:
current_maxArea = max(current_maxArea, (end - start) * height[start])
while height[start] <= min_start_end:
start += 1
if start == end:
break
else:
current_maxArea = max(current_maxArea, (end - start) * height[end])
while height[end] <= min_start_end:
end -= 1
if start == end:
break
return current_maxArea