数组
数组变换
#方法:根据规则,并用上递归调用。注意要额外复制一份数组
class Solution:
def transformArray(self, arr: List[int]) -> List[int]:
n = len(arr)
arr_new = copy.copy(arr)
for i in range(1,n-1):
if (arr[i] < arr[i-1] and arr[i] < arr[i+1]) :
arr_new[i] = arr_new[i] + 1
elif (arr[i] > arr[i-1] and arr[i] > arr[i+1]):
arr_new[i] = arr_new[i] - 1
if arr == arr_new:
return arr_new
else:
return self.transformArray(arr_new)
打乱数组
class Solution:
def __init__(self, nums: List[int]):
self.array = nums
self.original = list(nums)
def reset(self) -> List[int]:
"""
Resets the array to its original configuration and return it.
"""
self.array = list(self.original)
return self.array
def shuffle(self) -> List[int]:
"""
Returns a random shuffling of the array.
"""
random.shuffle(self.array)
return self.array
#方法一:
def shuffle(self):
aux = list(self.array)
for idx in range(len(self.array)):
remove_idx = random.randrange(len(aux))
self.array[idx] = aux.pop(remove_idx)
return self.array
# 方法二
def shuffle(self):
for i in range(len(self.array)):
swap_idx = random.randrange(i, len(self.array))
self.array[i], self.array[swap_idx] = self.array[swap_idx], self.array[i]
return self.array
旋转数组
# 方法一:逐个插入
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
k = k % len(nums)
for i in range(k):
nums.insert(0,nums.pop())
# 方法二: 数组切片
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
l = len(nums)
k = k % l
nums[:] = nums[l-k:] + nums[:l-k]
# 方法三:三次翻转
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
l = len(nums)
k = k%l
self.reverse(nums,0,l-1)
self.reverse(nums,0,k-1)
self.reverse(nums,k,l-1)
def reverse(self,nums,start,end):
while start < end:
nums[start],nums[end] = nums[end],nums[start]
start += 1
end -= 1
三数之和——双指针
def threesum(nums,target):
nums = sorted(nums)
n = len(nums)
result = []
if n < 3:
return []
for i in range(n):
L = i + 1
R = n - 1
if i > 0 and nums[i] == nums[i-1] :
continue
while(L<R):
if nums[i] + nums[L] +nums[R] == target:
result.append([nums[i],nums[L],nums[R]])
while L < R and nums[L] == nums[L+1]:
L = L + 1
while L < R and nums[R] == nums[R-1]:
R = R - 1
L = L + 1
R = R - 1
elif nums[i] + nums[L] +nums[R] > target:
R = R - 1
else:
L = L + 1
return result
最接近的三数之和——双指针
def close_threesum(nums,target):
n = len(nums)
nums = sorted(nums)
result = nums[0] + nums[1] + nums[2]
for i in range(n):
if i > 0 and nums[i] == nums[i-1]:
continue
L = i + 1
R = n - 1
while L < R:
ans = nums[i] + nums[L] + nums[R]
print(L,R,ans)
if ans == target:
return ans
if abs(result-target) > abs(ans- target):
result = ans
if ans > target:
R = R - 1
else:
L = L + 1
print('epoch = --------------',i,result)
return result
较小的三数之和——双指针
def small_threesum(nums,target):
n = len(nums)
nums = sorted(nums)
result = 0
for i in range(n):
L = i + 1
R = n - 1
while L < R:
while L < R and nums[i] + nums[L] + nums[R] >= target:
R = R - 1
if nums[i] + nums[L] + nums[R] < target:
result = result + R - L
L = L + 1
return result
两个有序数组的中位数
def findMedianSortedArrays(nums1, nums2):
m = len(nums1)
n = len(nums2)
if m > n:
nums1,nums2,m,n = nums2,nums1,n,m
if n == 0:
return ValueError
imin,imax,half = 0, m, (m+n+1)//2
while imin <= imax:
i = (imin + imax) // 2
j = half - i
if i < m and nums1[i] < nums2[j-1]:
imin = imin + 1
elif i > 0 and nums1[i-1] > nums2[j]:
imax = imax - 1
else:
if i == 0: max_left = nums2[j-1]
elif j == 0 :max_left = nums1[i-1]
else: max_left = max(nums1[i-1],nums2[j-1])
if i == m:min_right = nums2[j]
elif j==n:min_right = nums1[i]
else: min_right = min(nums1[i],nums2[j])
if (m+n)% 2 == 1:
return max_left
return (max_left+min_right) / 2.0
4.19更新
46. 全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def sort(nums,k):
n = len(nums[0])
ans = []
for lis in nums:
for i in range(k,n):
c_lis = lis.copy()
c_lis[k],c_lis[i] = c_lis[i],c_lis[k]
ans.append(c_lis)
return ans
num = [nums]
for k in range(len(nums)):
num = sort(num,k)
return num
个人做法,即0位置与1到n-1位置交换,1位置与2到n-1位置交换。。。。
能解,但是会用到额外的空间;而且与回溯法类似?
看看一行python的解法
def permute(self, nums: List[int]) -> List[List[int]]:
return list(itertools.permutations(nums))
以及回溯算法的解法
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
def backtrack(nums, tmp):
if not nums:
res.append(tmp)
return
for i in range(len(nums)):
backtrack(nums[:i] + nums[i+1:], tmp + [nums[i]])
backtrack(nums, [])
return res
这里回溯体现在什么地方呢,就是每次res.append()之后,return这个地方,总之应该会有清空tmp的作用吧?还没尝试。
字符串相关
字母大小写全排列
给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合。
class Solution:
'''
def letterCasePermutation(self, S: str) -> List[str]:
f = lambda x: (x.lower(), x.upper()) if x.isalpha() else x
return map("".join, itertools.product(*map(f, S)))
'''
def letterCasePermutation(self, S: str) -> List[str]:
ans = [[]]
for char in S:
n = len(ans)
if char.isalpha():
for i in range(n):
ans.append(ans[i][:])
ans[i].append(char.lower())
ans[n+i].append(char.upper())
else:
for i in range(n):
ans[i].append(char)
return map("".join, ans)
两个办法,一个是看成笛卡尔积,也就是从所有集合中选择每种可能的组合。
另一个是递归法,这里要学习的写法是
for i in range(n):
ans.append(ans[i][:])
字符串相加
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
class Solution:
def addStrings(self, num1: str, num2: str) -> str:
i,j = len(num1)-1,len(num2)-1
head = 0
res = ''
while i >= 0 or j >= 0:
add1 = int(num1[i]) if i >= 0 else 0
add2 = int(num2[j]) if j >= 0 else 0
sum_ = add1 + add2 + head
head = sum_ // 10
res = str(sum_ % 10) + res
i -=1
j -= 1
return '1' + res if head != 0 else res
两个指针,从尾往头扫,相加。
1071. 字符串的最大公因子
对于字符串 S 和 T,只有在 S = T + … + T(T 与自身连接 1 次或多次)时,我们才认定 “T 能除尽 S”。
返回最长字符串 X,要求满足 X 能除尽 str1 且 X 能除尽 str2。
class Solution:
def gcdOfStrings(self, str1: str, str2: str) -> str:
if str1 == str2:
return str1
str0 = str1 if len(str1)< len(str2) else str2 ##枚举法来解决
n =len(str0)
for i in range(n,0,-1):
ans = str0[:i]
if len(str1) % len(ans) == 0 and len(str2) % len(ans) == 0:
l1 = len(str1) // len(ans)
l2 = len(str2) // len(ans)
if str1 == l1 * ans and str2 == l2 *ans:
return ans
return ''
这里用的是暴力的枚举法,由于是最大公因子,所以就从后往前慢慢缩小,找到能整除的子串
443. 压缩字符串、
给定一组字符,使用原地算法将其压缩。
压缩后的长度必须始终小于或等于原数组长度。
数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。
在完成原地修改输入数组后,返回数组的新长度。
class Solution:
def compress(self, chars: List[str]) -> int:
n = len(chars)
pos = 0
cnt = 1
if len(chars) == 1:
return len(chars)
for i,value in enumerate(chars):
if i < n-1 and chars[i + 1] == value :
cnt = cnt + 1
else:
chars[pos] = value
pos = pos + 1
if cnt != 1:
for j in str(cnt):
chars[pos] = j
pos = pos + 1
cnt = 1
for i in range(pos,n):
chars.pop(-1)
return len(chars)
一个指针记录位置,一个计数器统计次数。
遍历,后一位与当前相同,计数器计数。
不同,则记录下当前值,指针进一位,开始记录计数器的数字。
最后把多余的清除
758. 字符串中的加粗单词
给定一个关键词集合 words 和一个字符串 S,将所有 S 中出现的关键词加粗。所有在标签 和 中的字母都会加粗。
返回的字符串需要使用尽可能少的标签,当然标签应形成有效的组合。
例如,给定 words = [“ab”, “bc”] 和 S = “aabcd”,需要返回 “aabcd”。注意返回 “aabcd” 会使用更多的标签,因此是错误的。
import re
class Solution:
def boldWords(self, words: List[str], S: str) -> str:
idx = []
for word in words:
loc = S.find(word)
while loc != -1:
idx.append([loc, loc + len(word)])
loc = S.find(word, loc + 1)
idx = sorted(idx)
res = self.merge(idx)
lis = list(S)
i = 0
for pos in res:
lis.insert(pos[0]+i,'<b>')
i += 1
lis.insert(pos[1]+i, '</b>')
i += 1
result = ''.join(lis)
return result
def merge( self,intervals):
if len(intervals) == 0:
return []
res = []
intervals = list(sorted(intervals))
low = intervals[0][0]
high = intervals[0][1]
for i in range(1,len(intervals)):
if high >= intervals[i][0]:
if high < intervals[i][1]:
high = intervals[i][1]
else:
res.append([low,high])
low = intervals[i][0]
high = intervals[i][1]
res.append([low,high])
return res
两部分:
找到单词所在位置,区间的形式;
这部分一开始用正则表达,但对于ee与eee这种情况,正则表达式我不知道该如何解决;
上面的写法是参照别人的。string.find(),如果超过当前位置,则会返回-1
合并区间,根据区间位置插入。