LeetCode 习题 1 - 10
- 1. 两数之和
- 2. 两数相加
- 3. 无重复字符的最长子串
- 4. 寻找两个正序数组的中位数
- 5. 最长回文子串
- 6. N 字形变换
- 7. 整数反转
- 8. 字符串转换整数 (atoi)
- 9. 回文数
- 10. 正则表达式匹配
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
通过次数4,194,521提交次数7,931,754
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第一遍,暴力计算,复杂度 O(n^2)
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
n = len(nums)
for i in range(n-1):
for j in range(i+1,n):
if nums[i] + nums[j] == target:
return [i,j]
竟然还能击败这么多人吗?难道这不是最土的办法吗?
然后想办法优化下,利用一下 python 本身的方法
第二遍,排序后计算,嗯,其实我也不知道复杂度是多少,但他就是运行时间减少了那么多
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
arr = [_ for _ in nums]
arr.sort(reverse=True)
n = len(arr)
for i in range(n-1):
for j in range(1,n):
if arr[i] + arr[j] == target:
pos = nums.index(arr[i])
if arr[i] != arr[j]:
return [pos,nums.index(arr[j])]
else:
return [pos,nums[pos+1:].index(arr[j])+pos+1]
第三遍,利用集合set来看看
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
n = {}
for i in range(len(nums)):
if nums[i] in n.keys():
n[nums[i]] = (n[nums[i]] + [i])[:2]
else:
n[nums[i]] = [i]
for i in n.keys():
if target == i * 2:
if len(n[i])>1:
return n[i]
continue
if target - i in n.keys():
return [n[i][0],n[target - i][0]]
https://leetcode.cn/submissions/detail/403539238/
内存消耗越来越大了。。。到底怎么能把内存消耗也减掉一些呢
第四遍,实在搞不懂,抄一下官方题解吧
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hashtable = dict()
for i, num in enumerate(nums):
if target - num in hashtable:
return [hashtable[target - num], i]
hashtable[nums[i]] = i
return []
????诧异了,执行时间居然比我第三遍的还多一点。。。吓得我多执行了几次第三遍代码,哦,赶巧了啊,平均用时还是40多一点,嗯这个题目就确定了,用hashtable、dict之类的方法就是最好的办法了
2. 两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
提示:
每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零
通过次数1,641,150提交次数3,875,235
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/add-two-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
老顾是个野路子,链表是个啥东西也都是最近才开始接触,平时工作里真就没用上过这东西。。。
还好题目中代码给了个 ListNode 的构造,不用一头雾水的琢磨了,然后大概也明白 Node 是个什么东西了,就琢磨了第一个版本的代码
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
u = l1
d = l2
r = ListNode()
z = r
f = 0
n = 0
while u or d or n>0:
if f:
r.next = ListNode()
r = r.next
s = (u.val if u else 0) + (d.val if d else 0) + n
r.val = s % 10
n = s // 10
u = u.next if u else None
d = d.next if d else None
f = 1
return z
其实这个题,就是逆序的10进制加法,不过所有数都是倒着的,第一个是各位数,第二位是十位数,第三位是千位数这样的。。。最后返回的链表要求也是逆序的,这就ok
嗯。。。。用了很多没啥意义的变量,纯粹是懒得改了,提交的时候就是这样,算法好像也没啥算法,老顾对链表真的不懂,不知道这种单向链表(也不知道对不对)怎么就能方便的返回每个节点的值,就这么用本办法弄出来了,然后开始学习,去看官方题解。。。好吧,竟然没有 python 版本的题解,而 java 的和 c# 的,居然方法内的内容一毛一样。。。除了变量更容易让人读懂,和老顾的写法也没啥本质区别了。。。瞎猫碰到死耗子了
3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
通过次数2,182,219提交次数5,580,531
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
还好,这个题目看着就很简单,嗯,从第一个字符遍历,然后记录遍历的起始位置,碰到重复的字符,记录长度,并和最大长度比较,然后遍历的起始位置从重复的字符后一个开始。。。嗯,思路很清晰,来,写代码了
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
n = len(s)
if n<2:
return n
mx = 1
# 576ms,15.1mb
pos = 0
while pos < n:
nxt = 1
if pos + nxt == n:
break
final = 0
while s[pos + nxt] not in s[pos:pos + nxt]:
if mx < nxt + 1:
mx = nxt + 1
nxt += 1
if pos + nxt == n:
final = 1
break
if final == 1:
break
pos += s[pos:pos + nxt].index(s[pos + nxt]) + 1
return mx
额。。。。这个成绩有点惨不忍睹啊。。。。倒数的前8%。。。。。琢磨琢磨怎么给优化一下,思路应该没什么大问题吧?
嗯,pos 和 nxt 意义不大,不如取消这两个变量,直接用字符串代替,也不再用 s[pos:pos+nxt] 方式计算,直接用一个字符串代替这一堆
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
n = len(s)
if n<2:
return n
mx = 1
# 100ms,15.1mb
l = ''
for i in range(n):
while s[i] in l:
l = l[1:]
l += s[i]
mx = max(mx,len(l))
return mx
嗯。。。。看着舒服很多,这次不至于那么惨的成绩了吧,看看先
https://leetcode.cn/submissions/detail/403660974/
嗯,碰到一次赶巧的成绩,那估计我的这个代码也没啥问题了,翻了翻官方题解。。。。好吧,不能说没啥区别,只能说完全一个路子
4. 寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
通过次数889,905提交次数2,135,574
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
其实,题目到是真不难,问题在于要理解题意。。。开始没弄明白,什么叫中位数,看了看两个示例,还以为是平均数,一提交,人家不认。。。
额。。。。那中位数是啥?难道是两个数组中合并后,最中间的那一个或两个数的平均数?那就再试试吧
一通操作猛如虎,还好成绩不是250
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
arr = nums1 + nums2
arr.sort()
n = (len(arr) + 1) // 2 - 1
if len(arr) % 2 == 1:
return arr[n]
else:
return (arr[n] + arr[n+1]) / 2
当然,这里的运算取巧了,毕竟不管 js 也好,python 也好,排序已经不是主要目标了,通常都会直接用系统提供的办法完成,这次只是确定了中位数的概念。。。。嗯,试着不用自身的 sort ,自己来按顺序插入数字。。。反而慢了一半,算了,不折腾了。。。估计这个题考的目的就是排序插入新数组,70ms完成应该也可以了,就当我过了,嘿嘿
说句题外话,这个题目的评价难度居然是困难,没看出困难在哪里。。。。
5. 最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd”
输出:“bb”
提示:
1 <= s.length <= 1000
s 仅由数字和英文字母组成
通过次数1,322,154提交次数3,534,763
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第一遍,还是暴力思路,这人呐,脑子闲置的久了,就用不上了。。。
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
if n < 2:
return s
r = s[0]
for i in range(n):
for j in range(i+1,n+1):
if s[i:j] == s[i:j][::-1]:
if j-i>len(r):
r = s[i:j]
return r
然后,不出所料的没有能通过
这个是真没想法啊。。。。只好去看题解,嗯嗯嗯嗯,学了很多写法,印象最深刻的,并且自己能理解透的,也就是那个Manacher算法。。。设计真精巧啊
class Solution:
def longestPalindrome(self, s: str) -> str:
r = ''
t = '^#' + '#'.join(s) + '#$'
n = len(t)
p = [0 for _ in range(n)]
for i in range(1,n-1):
while t[i - p[i] - 1] == t[i + p[i] + 1]:
p[i] += 1
mx = max(p)
idx = p.index(mx)
b = (idx - mx) // 2
r = s[b:b+mx]
return r
这。。。。跑了好几遍,基本都在1000ms左右?点开提交结果一看。。。排不上号啊。。。
看来,还得继续学习,而且看官方题解已经不够了,得学别人的写法了,好在,可以点执行用时分布里的时间点看别人的代码,真棒
先找了个900ms左右的答案。。。嗯中心扩散法,学习学习
# 以下内容抄自leetcode第5题908ms答案,实际运行能达到600ms左右
class Solution:
def longestPalindrome(self, s: str) -> str:
#暴力解法
# cur_str = max_str = ''
# for i in range(len(s)):
# for j in s[i:]:
# cur_str += j
# if cur_str == cur_str[::-1] and len(cur_str) > len(max_str):
# max_str = cur_str
# cur_str = ''
# return max_str
#中心扩散法
left = right = start = 0
cur_len = max_len = 1
for i in range(len(s)):
left = i - 1
right = i +1
while left >= 0 and s[i] == s[left]:
left -= 1
cur_len += 1
while right < len(s) and s[i] == s[right]:
right += 1
cur_len += 1
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
cur_len += 2
print(s[left], cur_len,end ='QWQ ')
while cur_len > max_len:
max_len = cur_len
start = left + 1
cur_len = 1 #少了这句找了一小时bug
print(start, end='')
print(max_len)
return s[start: start + max_len]
# 以下内容抄自leetcode第5题800ms答案,实际运行能达到600ms左右
class Solution:
def longestPalindrome(self, s: str) -> str:
palindrome = ''
for i in range(len(s)):
len1 = len(self.getLongestPalindrome(s,i,i))
if len1> len(palindrome):
palindrome = self.getLongestPalindrome(s,i,i)
len2 = len(self.getLongestPalindrome(s,i,i+1))
if len2> len(palindrome):
palindrome = self.getLongestPalindrome(s,i,i+1)
return palindrome
def getLongestPalindrome(self,s,l,r):
while l>=0 and r<len(s) and s[l]==s[r]:
l-=1
r+=1
return s[l+1:r]
可惜只能看到答案,不知道是哪位同学提交的,嗯,都是提交的源代码,我一个字符都没改动过的。
这两个答案都是中心扩散法,老顾就不说题解了,自己写一遍试试看,其他同学关于中心扩散法的说明很多,官方题解里也有
# 老顾自己搞一版
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
if n < 2 or s == s[::-1]:
return s
t = s[0]
for i in range(n):
mx = 1
while i - mx >= 0 and i + mx < n and s[i - mx] == s[i + mx]:
r = s[i - mx:i + mx + 1]
mx += 1
if len(r) > len(t):
t = r
mx = 1
while i - mx + 1 >= 0 and i + mx < n and s[i - mx + 1] == s[i + mx]:
r = s[i - mx + 1:i + mx + 1]
mx += 1
if len(r) > len(t):
t = r
return t
额。。。。。。这执行用时超出我的预料啊,我还以为也就600ms左右呢。。。。
然后,我们来抄个最厉害的答案吧,40ms执行时间的。。。
# 以下内容抄自leetcode第5题40ms答案
class Solution:
def longestPalindrome(self, s: str) -> str:
if len(s) < 2 or s == s[::-1]:
return s
res = s[0]
maxlen = 1
for i in range(1, len(s)):
odd = s[i - maxlen - 1: i + 1]
even = s[i - maxlen: i + 1]
if even == even[::-1] and i - maxlen >= 0:
res = even
maxlen += 1
continue
if odd == odd[::-1] and i - maxlen - 1 >= 0:
res = odd
maxlen += 2
continue
return res
https://leetcode.cn/submissions/detail/403938742/
肯定是我的电脑和网络问题,竟然跑了几次都没挨到40,人家的最高成绩是36ms。。。。
这位的办法更直接,直接判断当前位置按最大长度中心扩散,得到单双两个字符串,如果其中一个是回文。。。省略了前边的判定,估计在python中好用,其他语言环境就难言了
另一个更暴力的
# 以下内容抄自leetcode第5题56ms答案
class Solution:
def longestPalindrome(self, s: str) -> str:#
res=''
for i in range(len(s)):
start=max(0,i-len(res)-1)
temp=s[start:i+1]
if temp==temp[::-1]:
res=temp
else:
temp=temp[1:]
if temp==temp[::-1]:
res=temp
return res
效率虽然略有不如前边的,但他的思路更简洁,实现起来更简单啊。。。。
抄个java的40ms看看。。。其实也差不多。。。
// 以下内容抄自leetcode第5题40ms答案
class Solution {
public String longestPalindrome(String s) {
if(s.length()==0){
return s;
}
if(s.length()==1){
return s;
}
if(s.length()==2){
if(s.charAt(0)==s.charAt(1)){
return s;
}else{
return s.substring(0,1);
}
}
String result="";
for(int i =1;i<s.length();i++){
char a = s.charAt(i);
int start = i-1;
int end = i+1;
while (start>=0&&end<=s.length()-1){
if(end-i==1){
while (s.charAt(start)==a){
start -= 1;
if(start<0){
break;
}
}
while (s.charAt(end)==a){
end +=1;
if(end>s.length()-1){
break;
}
}
String temp = s.substring(start+1,end);
if(temp.length()>result.length()){
result=temp;
}
}
if(start<0||end>s.length()-1){
break;
}
if(s.charAt(start)==s.charAt(end)){
String temp = s.substring(start,end+1);
if(temp.length()>result.length()){
result=temp;
}
start--;
end++;
continue;
}else{
break;
}
}
}
return result;
}
}
也是中心扩散法,嗯确定了,manacher方法很精巧,很容易记,但效率真不如中心扩散
6. N 字形变换
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入:s = “PAYPALISHIRING”, numRows = 3
输出:“PAHNAPLSIIGYIR”
示例 2:
输入:s = “PAYPALISHIRING”, numRows = 4
输出:“PINALSIGYAHRPI”
解释:
P I N
A L S I G
Y A H R
P I
示例 3:
输入:s = “A”, numRows = 1
输出:“A”
提示:
1 <= s.length <= 1000
s 由英文字母(小写和大写)、‘,’ 和 ‘.’ 组成
1 <= numRows <= 1000
通过次数531,132提交次数1,019,546
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/zigzag-conversion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
呦,这个应该不难吧?结果老顾自己琢磨了半天,才弄出第一个版本
class Solution:
def convert(self, s: str, numRows: int) -> str:
n = len(s)
if n <= numRows:
return s
if numRows==1:
return s
r = ['' for _ in range(numRows)]
x = numRows*2-2
for i in range(numRows):
r[i] = [s[_] if _%x==i or (_%x>=numRows and numRows-(_%x-numRows+1)-1==i) else '' for _ in range(n)]
#for i in r:
# print(''.join(i))
return ''.join([''.join(i) for i in r])
其实就是一个折叠位置的取余与原有高度的差问题。。。嗯,这个效率太感人了
惨不忍睹啊。。赶紧简化 代码
class Solution:
def convert(self, s: str, numRows: int) -> str:
n = len(s)
if n <= numRows:
return s
if numRows==1:
return s
x = numRows*2-2
r = ['' for _ in range(numRows)]
for i in range(n):
r[min(i % x,x-i%x)] += s[i]
return ''.join(r)
好像也诶怎么动,就是把按行循环改成按字符循环。。。第一版是按行从字符串里提取应该在该行的字符,第二版是按字符分配到应该去的行。。。。结果效率。。。
效率还是不错的。。。问题是才53%??
这得抄作业?来个36ms的答案看看!
# 以下内容抄自leetcode第6题36ms答案
class Solution:
def convert(self, s: str, numRows: int) -> str:
ans = ['']*numRows
flag = -1
cnt = 0
if numRows<2:
return s
for ch in s:
ans[cnt] +=ch
if cnt ==0 or cnt ==numRows-1:
flag = flag * -1
cnt += flag
return ''.join(ans)
额。。。。感觉差不多啊,为什么比不过呢?算了,这个答案分布,基本就差那么几ms,老顾是不懂的了,不跟你们这帮牲口拼了,继续做下一题去了
7. 整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例 1:
输入:x = 123
输出:321
示例 2:
输入:x = -123
输出:-321
示例 3:
输入:x = 120
输出:21
示例 4:
输入:x = 0
输出:0
提示:
-231 <= x <= 231 - 1
通过次数1,150,381提交次数3,247,643
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reverse-integer
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
Hmmmmmmm,我的电脑难道是32位的?
class Solution:
def reverse(self, x: int) -> int:
s= str(x)
f = 1
if s[0] == '-':
f = -1
s = s[1:]
e = int(s[::-1]) * f
return e if e>=-2**31 and e<=2**31-1 else 0
额。。。。。。我都作弊了,居然还不是头部10%?
算了,这个题还是按照不作弊的方式自己尝试下吧。
class Solution:
def reverse(self, x: int) -> int:
y = 0
z = 1
if x < 0:
z = -1
x *= z
while x > 0:
y = y * 10 + x % 10
x //= 10
y *= z
if y > (2**31 - 1) or y < (2**31 * -1):
return 0
return y
https://leetcode.cn/submissions/detail/403955924/
嗯。。。。老顾真的不知道怎么装作不支持64位。。。所以最后的那个比大小估计是有问题的,然后答案估计也很集中在几个时间点上,就不抄答案了这次
8. 字符串转换整数 (atoi)
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
读入字符串并丢弃无用的前导空格
检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
如果整数数超过 32 位有符号整数范围 [−2^31, 2^31 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −2^31 ,大于 2^31 − 1 的整数应该被固定为 2^31 − 1 。
返回整数作为最终结果。
注意:
本题中的空白字符只包括空格字符 ’ ’ 。
除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
示例 1:
输入:s = “42”
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:“42”(当前没有读入字符,因为没有前导空格)
^
第 2 步:“42”(当前没有读入字符,因为这里不存在 ‘-’ 或者 ‘+’)
^
第 3 步:“42”(读入 “42”)
^
解析得到整数 42 。
由于 “42” 在范围 [-2^31, 2^31 - 1] 内,最终结果为 42 。
示例 2:
输入:s = " -42"
输出:-42
解释:
第 1 步:" -42"(读入前导空格,但忽视掉)
^
第 2 步:" -42"(读入 ‘-’ 字符,所以结果应该是负数)
^
第 3 步:" -42"(读入 “42”)
^
解析得到整数 -42 。
由于 “-42” 在范围 [-2^31, 2^31 - 1] 内,最终结果为 -42 。
示例 3:
输入:s = “4193 with words”
输出:4193
解释:
第 1 步:“4193 with words”(当前没有读入字符,因为没有前导空格)
^
第 2 步:“4193 with words”(当前没有读入字符,因为这里不存在 ‘-’ 或者 ‘+’)
^
第 3 步:“4193 with words”(读入 “4193”;由于下一个字符不是一个数字,所以读入停止)
^
解析得到整数 4193 。
由于 “4193” 在范围 [-2^31, 2^31 - 1] 内,最终结果为 4193 。
提示:
0 <= s.length <= 200
s 由英文字母(大写和小写)、数字(0-9)、’ ‘、’+‘、’-’ 和 ‘.’ 组成
通过次数544,287提交次数2,544,799
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/string-to-integer-atoi
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
嗯,这个题其实非常简单,主要就是,从读入符号看是,后边必须是数字这么一个隐藏条件
class Solution:
def myAtoi(self, s: str) -> int:
s = s.strip()
x = ''
f = 1
if len(s)==0:
return 0
if s[0] in '+-':
if s[0] == '-':
f *= -1
s = s[1:]
while len(s)>0 and s[0].isnumeric():
x += s[0]
s = s[1:]
e = int(x) if len(x)>0 and x != '-' else 0
e *= f
if e < 2**31 * -1:
e = 2**31 * -1
if e >= 2**31:
e = 2**31 - 1
return e
牲口太多了。。。才30%不到的名次
竟然还有20ms的答案。。。比不了比不了
9. 回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。
示例 1:
输入:x = 121
输出:true
示例 2:
输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。
提示:
-2^31 <= x <= 2^31 - 1
进阶:你能不将整数转为字符串来解决这个问题吗?
通过次数1,279,736提交次数2,268,913
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/palindrome-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution:
def isPalindrome(self, x: int) -> bool:
return str(x) == str(x)[::-1]
你说不转字符串我就不转?
嗯,那就不转吧
class Solution:
def isPalindrome(self, x: int) -> bool:
if x == 0:
return True
if x < 0 or x % 10 == 0:
return False
y = x
z = 0
while y > 0:
z = z * 10 + y % 10
y //= 10
if y == z:
return True
return x == z
最好成绩52ms,题目评价简单,也就这样了
10. 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
'’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 1:
输入:s = “aa”, p = “a”
输出:false
解释:“a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:s = “aa”, p = “a*”
输出:true
解释:因为 ‘’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:
输入:s = “ab”, p = "."
输出:true
解释:"." 表示可匹配零个或多个('’)任意字符(‘.’)。
提示:
1 <= s.length <= 20
1 <= p.length <= 30
s 只包含从 a-z 的小写字母。
p 只包含从 a-z 的小写字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符
通过次数345,735提交次数1,118,182
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/regular-expression-matching
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
老顾自认自己的正则还不错,这个题目就是根据正则来的,不过只要求实现长度*和字符集.
先用正则包来完成下看看情况
import re
class Solution:
def isMatch(self, s: str, p: str) -> bool:
return True if re.match(p+'$',s) else False
我去。。。。这成绩倒数了啊,大佬这么多,都自己实现的正则算法?
嗯,自己写个尝试看看,第一步,整理正则,为什么要整理正则呢?因为很多时候,新手的正则写得很冗余,有效部分其实并不多
# 两个正则片段,完全等价的哦
a*b*.*c* === .*
a*aaa === a{3,}
a*a*a*a*a*a* === a*
a*.*b*.*a*aa*a* === .*a{1,}
这么一整理,需要处理的片段就会少很多了
def formatRegexPattern(self,p):
pattern = []
for i in p:
if len(pattern) == 0:
pattern.append({'c':i,'l':1,'r':1})
continue
if i == '*':
pattern[-1]['r'] = -1
pattern[-1]['l'] -= 1
while len(pattern) > 1 and pattern[-1]['c'] == '.':
isPop = False
if pattern[-2]['r'] == -1 and pattern[-2]['l'] == 0:
pattern.pop(-2)
isPop = True
if not isPop:
break
while len(pattern) > 1 and pattern[-2]['c'] == '.' and pattern[-2]['r'] == -1:
isPop = False
if pattern[-1]['l'] == 0:# and pattern[-2]['l'] == 0:
pattern.pop(-1)
isPop = True
if not isPop:
break
while len(pattern) > 1 and pattern[-1]['c'] == '.' and pattern[-2]['c'] == '.':
pattern[-2]['l'] += pattern[-1]['l']
if pattern[-2]['r'] == -1 or pattern[-1]['r'] == -1:
pattern[-2]['r'] = -1
pattern.pop(-1)
continue
if i == pattern[-1]['c']:
pattern[-1]['l'] += 1
pattern[-1]['r'] += 1 if pattern[-1]['r'] > 0 else 0
continue
pattern.append({'c':i,'l':1,'r':1})
return pattern
嗯,弄好了正则合并后,老顾开始琢磨怎么实现正则了,开始写了一大片代码。。。问题是没递归,没调用,纯用循环判断各种情况,最后写不下去了。。。。自己把自己恶心到了
换个思路,正则匹配是按片段进行的,当上一个片段符合,就匹配下一个片段
那么,用递归去匹配当前片段,当前字符串,然后将剩余的片段递归到下一次匹配,传递剩余字符串就好了
再然后,唯一需要注意的就是长度问题了,最后好歹实现出来了,帖个代码先
class Solution:
def formatRegexPattern(self,p):
pattern = []
for i in p:
if len(pattern) == 0:
pattern.append({'c':i,'l':1,'r':1})
continue
if i == '*':
pattern[-1]['r'] = -1
pattern[-1]['l'] -= 1
while len(pattern) > 1 and pattern[-1]['c'] == '.':
isPop = False
if pattern[-2]['r'] == -1 and pattern[-2]['l'] == 0:
pattern.pop(-2)
isPop = True
if not isPop:
break
while len(pattern) > 1 and pattern[-2]['c'] == '.' and pattern[-2]['r'] == -1:
isPop = False
if pattern[-1]['l'] == 0:# and pattern[-2]['l'] == 0:
pattern.pop(-1)
isPop = True
if not isPop:
break
while len(pattern) > 1 and pattern[-1]['c'] == '.' and pattern[-2]['c'] == '.':
pattern[-2]['l'] += pattern[-1]['l']
if pattern[-2]['r'] == -1 or pattern[-1]['r'] == -1:
pattern[-2]['r'] = -1
pattern.pop(-1)
continue
if i == pattern[-1]['c']:
pattern[-1]['l'] += 1
pattern[-1]['r'] += 1 if pattern[-1]['r'] > 0 else 0
continue
pattern.append({'c':i,'l':1,'r':1})
return pattern
def IsMatch(self,s,p):
if len(s) == 0 and len(p) == 0:
return True
if len(s) == 0 and sum([n['l'] for n in p]) > 0:
return False
if len(s) == 0 and sum([n['l'] for n in p]) == 0:
return True
if len(s) > 0 and len(p) == 0:
return False
r = False
f = p[0]
c = f['c']
l = f['l']
m = f['r']
if l > 0:
if l > len(s):
return False
v = s[:l]
if c != '.' and c * l != v:
return False
s = s[l:]
if m > l:
for i in range(m - l + 1):
if c * i == s[:i] or c == '.':
r = r or self.IsMatch(s[i:],p[1:])
if r:
break
elif m == -1:
for i in range(len(s) + 1):
if c * i == s[:i] or c == '.':
r = r or self.IsMatch(s[i:],p[1:])
if r:
break
else:
r = r or self.IsMatch(s,p[1:])
return r
def isMatch(self, s: str, p: str) -> bool:
pattern = self.formatRegexPattern(p)
return self.IsMatch(s,pattern)
https://leetcode.cn/submissions/detail/404116311/
呦呵,成绩还不错,差一点就到头部了,一个正则实现琢磨了两天,终于搞定,学习告一段落,下次继续学习