LeetCode四题合集 1,2,3,167
第三题:
题目:给定一个字符串,找出该字符串当中无重复字符的最长子串的长度
例如:abcabcb 返回 3,因为最长子串为abc
第一次操作:
1.想法:既然时间复杂度的考量无非就是一个遍历时每次前进的步数,即当遇到相同字符时后退的步数,所以刚开始的想法是,每次遍历到相同字符的时候,都从这个字符串中该字符的下一个位置重新开始
例如:abcabcb 遇到a时从上一个a所在地的下一个字符 b开始继续遍历匹配,同时比较当前最长字符串长度和当前子串长度进行比较,如果子串长度大于最长字符串,则将当前子串替代为最长字符串。
2.代码如下:
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
search_dict = {}
str_model = ""
i = 0
longest_str = ""#用于记录最长子串
max_i = len(s)
while(i < max_i):
if s[i] not in search_dict.keys():
search_dict[s[i]] = i #记录当前字符所在位置
str_model += s[i]
if len(str_model) > len(longest_str):
longest_str = str_model
i += 1
elif s[i] in search_dict.keys():
i = search_dict[s[i]] + 1 #重新开始匹配的位置
str_model = ""
search_dict.clear()
return len(longest_str)
但是这样的情况理论上最大时间复杂度仍为O(n2)所以在执行代码时在最后几个测试用例中,显示超过时间限制,那么问题就来了,如何优化?
既然想要优化时间复杂度,而时间复杂度跟每次跨越的步长有关,那么尽量在一次循环中做到更多的事情,并且不回溯,那么就可以做到时间复杂度O(N),同时更新hashmap来纪录当前已匹配的无重复字符最长子串的各个字符的位置,用与判断下一个字符是否重复,和切断重复字符之前的多于字符
代码如下:
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
search_dict = {}
str_model = ""
i = 0
longest_str = ""#用于记录最长子串
max_i = len(s)
i_start = 0 #记录匹配子串开始的index
while(i < max_i):
if s[i] not in search_dict.keys():
search_dict[s[i]] = i #记录当前字符所在位置
str_model += s[i]
if len(str_model) > len(longest_str):
longest_str = str_model
i += 1
# print(str_model)
elif s[i] in search_dict.keys():
i_last = search_dict[s[i]] + 1 #重新开始匹配的位置
# print(i,i_last,i_start)
if i_last < i_start:
str_model += s[i]
i_start = i_start
else:
str_model = s[i_last:i+1]
i_start = search_dict[s[i]] + 1
# print("str_model",str_model)
if len(str_model) > len(longest_str):
longest_str = str_model
search_dict[s[i]] = i
i += 1
# print(search_dict,'\n')
return len(longest_str)
相比于上一个想法,遇到相同字符的时候,直接回溯到上一个重复字符的下一个字符开始重新匹配,这次的想法是:在遇到重复字符的时候,不将已匹配的字符串清空,而是用上一个重复字符的下一个字符到当前重复字符来代替
第一题:
题目:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
想法:既然用暴力算法遍历的时间复杂度为O(N2),那就干脆,直接空间换时间,用一个哈希表来定位数组中的数
每取一个数number,判断 target - number 是否在表中就行了,同时每取一个number,同时把number从哈希表中排除
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
lens = len(nums)
j=-1
for i in range(1,lens):
temp = nums[:i]
if (target - nums[i]) in temp:
j = temp.index(target - nums[i])
break
if j>=0:
return [j,i]
if __name__ == "__main__":
nums = [2,7,11,15]
target = 9
sl = Solution()
print(sl.twoSum(nums,target))
第二题:
题目:两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
当时看到的想法就是基本加法的操作,将个位相加
如果和小于10,那就把和作为新链表的个位数
如果和大于10,那把**(和-10)**作为个位数,并且向前进位1
下一个位数相加的时候,就要把进位的数放入和中一起计算
# Definition for singly-linked list.
class ListNode(object):
def __init__(self, x):
self.val = x
self.next = None
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
head1 = l1
head2 = l2
remain = 0
head = ListNode(x=0)
p = head
while(head1 or head2):
if head1 == None:
val1 = 0
val2 = head2.val
head2 = head2.next
elif head2 == None:
val2 = 0
val1 = head1.val
head1 = head1.next
else:
val1 = head1.val
val2 = head2.val
head1 = head1.next
head2 = head2.next
val = val1 + val2 + remain
if val >= 10:
node_value = val-10
remain = 1
elif val < 10:
node_value = val
remain = 0
p.val = node_value
if head1 == None and head2 == None and remain == 0:
p.next = None
elif head1 == None and head2 == None and remain != 0:
new = ListNode(remain)
p.next = new
p = new
p.next = None
else:
new = ListNode(0)
p.next = new
p = new
return head
要注意几种常见的情况
- 链表长度不一样的时候(补0)
- 一个链表为空时
- 两数相加要产生新的位数的时候 例如:5+5 = 10
第167题:
题目:两数之和 II - 输入有序数组
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted
想法:如何利用有序这个条件
- 当暴力法遍历查找的时候,两个数之和大于target,就直接可以跳出一层循环,直接进行下一个第一层循环
问题:理论是Omax(N2)的时间复杂度 - 利用有序,从头跟尾同时开始遍历
如果和大于target:
大数往前移动
如果和小于target:
小数往后移动
如果大数 == 小数:
寻找失败
class Solution(object):
def twoSum(self, numbers, target):
"""
:type numbers: List[int]
:type target: int
:rtype: List[int]
"""
num = len(numbers)
i = 0
j = num
while(True):
if i == j:
return
if numbers[i] + numbers[j-1] == target:
return([i+1,j])
elif numbers[i] + numbers[j-1] > target:
j -= 1
elif numbers[i] + numbers[j-1] < target:
i += 1
if __name__ == "__main__":
nums = [2,7,11,15]
target = 9
sl = Solution()
print(sl.twoSum(nums,target))