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

要注意几种常见的情况

  1. 链表长度不一样的时候(补0)
  2. 一个链表为空时
  3. 两数相加要产生新的位数的时候 例如: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

想法:如何利用有序这个条件

  1. 当暴力法遍历查找的时候,两个数之和大于target,就直接可以跳出一层循环,直接进行下一个第一层循环
    问题:理论是Omax(N2)的时间复杂度
  2. 利用有序,从头跟尾同时开始遍历
    如果和大于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))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值