Leetcode腾讯算法题 -- 刷 出题指数为3颗星以上的题目 --第一部分

序言

最近找实习,每次都在算法题这里翻车,我实在太不甘心,理论上的知识点我已经很尽力,但是算法题刷的太少。所以我打算把Leetcode中腾讯的 刷出题指数为3颗星以上的题目 刷一次。

题目一:LT1-两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
输入:nums = [3,2,4], target = 6
输出:[1,2]

方法一:哈希表

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
    	dic = {}
    	for i in range(len(nums)):
    		if target - nums[i] in dic:
    			return [i, dic[target - nums[i] ]]		    		
    		dic[nums[i]]=i
    	return []

时间复杂度如何?也是O(N),因为有一个for loop
空间复杂度是O(N) 因为有哈希表的开销

方法二:二分搜索
但二分法可以让牺牲时间 来换取空间。
思路是从左到右 固定一个数,然后再剩下的区间找另一个值,这个值就可以用二分法来做。
这样做的时间复杂度是O(nlogn) 空间复杂度是O(1)
但发现 这不是升序列表。所以不能用二分法。
如果是升序列表 用双指针也可以做。

题目二:LT206-反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
输入:head = [1,2]
输出:[2,1]
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre, cur = None, head
        while cur: 
            nxt = cur.next 
            cur.next = pre #指向pre
            pre = cur 
            cur = nxt 
        return pre

时间复杂度是O(N);空间复杂度是O(1)

题目三:LT5- 最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串

输入:s = "babad"
输出:"bab"
输入:s = "cbbd"
输出:"bb"

这个明显用dp,动态规划。
那具体怎么说呢?
S作为横坐标;S‘作为S的反转字符,作为纵坐标
因为回子串 反过来 也是跟正过来一样的。
但是需要注意的是
abc234cba 和 反转字符是 abc432cba 这里也有相同的字符abc 但实际上abc不是回子串。
这就需要比较 i和j的情况。j是反转的指针;i是正字符串的指针。
通过比较反转字符尾j 在原来字符的位置 然后 再通过 回子串的长度 加上去 的得到的数 是否跟i一致。
如果是一致的话,就是会问字符了。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        s_rev = s[::-1]
        #创建dp
        N = len(s)
        dp = [[0]*(N+1) for _ in range(N+1)]

        len_ = 0 
        end_ = 0 

        for i in range(N):
            for j in range(N):
                if s[i] == s_rev[j]:
                    dp[i+1][j+1] = dp[i][j] + 1 

                    if (N-j-1) + (dp[i+1][j+1] -1)==i and len_ <= dp[i+1][j+1]: 
                        len_ = dp[i+1][j+1]
                        end_ = i  

        return s[end_-len_+1:end_+1]

时间复杂度是O(N^2)
空间复杂度是O(N)

题目四:LT3-无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度

输入: s = "abcabcbb"
输出: 3 
输入: s = "bbbbb"
输出: 1
输入: s = "pwwkew"
输出: 3

思路是:哈希表记录所有的 字符 :位置
因为这里求的是最长的不重复字符长度,
其实就是比较重复的两个字符之间的长度 的max
如果完全没有重复字符 就是很简单的 j-i
如果有重复的字符,i,j分别指向两个重复的字符中,长度也是j-i

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        #哈希表
        dic = {}
        ans = 0 
        i = -1 
        for j in range(len(s)):
            if s[j] in dic: 
                i = max(dic[s[j]], i)
            dic[s[j]]=j
            ans = max(ans,j-i)
        return ans  

时间和空间复杂度都是O(N)

题目五:LT2-两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807

输入:l1 = [0], l2 = [0]
输出:[0]

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

这道题可能比较难:
先做这道题:

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和

模拟相加过程

class Solution:
    def addStrings(self, num1: str, num2: str) -> str:
        res =''
        i,j,carry = len(num1)-1,len(num2)-1,0
        while i>=0 or j >=0:
            tmp1 = int(num1[i]) if i>=0 else 0
            tmp2 = int(num2[j]) if j>=0 else 0
            tmp = tmp1 + tmp2 + carry 
            carry = tmp//10
            res = str(tmp%10) +res
            i-=1
            j-=1
        return '1'+res if carry else res
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        head = point = ListNode() 
        carry = 0 
        while l1 or l2:
            new_point = ListNode() 
            if not l1:
                #当l1为none
                sum_ = l2.val + carry 
                carry = sum_//10
                new_point.val = sum_%10
                l2 = l2.next 
            elif not l2:
                #当脸l2 为None
                sum_ = l1.val+carry 
                carry = sum_//10
                new_point.val = sum_%10 
                l1 = l1.next 
            else:
                sum_ = l1.val + l2.val + carry
                carry = sum_//10
                new_point.val = sum_%10 
                l1 = l1.next
                l2 = l2.next 
            
            #赋值之后,开始接上链表
            point.next = new_point
            point = point.next 
        if carry:
            carry_= ListNode(1)
            point.next = carry_
        return head.next  

题目六:LT21-合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

输入:l1 = [], l2 = [0]
输出:[0]
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        if not l1: return l2 
        if not l2: return l1 

        if l1.val < l2.val: 
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1 
        else:
            l2.next = self.mergeTwoLists(l1, l2.next)
            return l2    	

题目七:LT4-寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

思路是 用之前学过的合并排序, 把两个数组合并成有序的数组。然后再直接输出中位数,只要分奇数和偶数来输出即可。

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        #回忆合并排序
        p,q=0,0
        ans = []
        while p<len(nums1) and q <len(nums2):
            if nums1[p] <= nums2[q]:
                ans.append(nums1[p])
                p+=1 
            else:
                ans.append(nums2[q])
                q+=1 
        ans += nums1[p:]
        ans += nums2[q:]

        N = len(ans)
        if N%2==0:
            return (ans[N//2]+ans[N//2 - 1])/2
        else:
            return ans[N//2]

时间复杂度:遍历全部数组 (m+n)
空间复杂度:开辟了一个数组,保存合并后的两个数组 O(m+n)
肯定会问 用其他方法是否会更好

方法二:二分查找
这种思路虽然可以将空间复杂度降到 O(1),但是时间复杂度仍是 O(m+n)

后面再补充。???
???
???

题目八:三元组之和为0

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
输入:nums = [0]
输出:[]

双指针

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
		N = len(nums)
		ans = []
		#specail cases 
		if not nums or N <3: return []
		nums.sort()
		for i in range(N):
			#如果当前值大于0,则后面不可能相加会为0 
			if nums[i]>0:return ans 
			#去掉没必要的重复值。
			if i >0 and nums[i]==nums[i-1]: continue
			#开始二分法
			bgn = i+1
			end = N-1 
			while bgn < end:
				if nums[i]+nums[bgn]+nums[end]==0:
					ans.append([nums[i],nums[bgn],nums[end]])
					#去除重复解
					while bgn < end and nums[bgn]==nums[bgn+1]:
						bgn += 1
					while bgn < end and nums[end]==nums[end-1]:
						end -= 1
					bgn += 1
					end -= 1 
				
				elif nums[i]+nums[bgn]+nums[end]>0:
					end -= 1 
				else:
					bgn +=1 
			return ans 

时间复杂度是O(N^2)
空间复杂度是O(1)

题目九:LT53-最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 

思路 单维度的动态规划
状态一:以-2结尾的连续子数组最大和是 -2
状态二:以1结尾的连续子数组最大和是 1 因为状态一是负数,所以不与状态一相加,直接返回本身。
状态三:以-3结尾的连续子数组最大和是-2,因为状态二是正数,可以与之相加。
状态四:以4结尾的连续子数组最大和是4 因为状态三是负数
状态五:以-1结尾的连续子数组最大和是3,因为前面状态是正,与之相加
状态六:以2结尾的连续子数组最大和是5 因为前面状态为正
状态七:以1结尾的连续子数组最大和是6 因为前面状态为正
。。。 同理

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0]*n
        dp[0] = nums[0]
        for i in range(1,n):
            if dp[i-1]>0: 
                dp[i] = dp[i-1] + nums[i]
            else:
                dp[i]=nums[i]
        return max(dp)

题目十:LT141-环形链表

给定一个链表,判断链表中是否有环。如果链表中存在环,则返回 true 。 否则,返回 false

思路是用快慢指标。如果是有环的话,快的指标迟早会追上慢指标。
如果慢指标与快指标相等,则返回return true

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
    	#special cases 
    	if not head or not head.next: return False 
		slow = head
		fast = head.next 
		while slow != fast:
			if not fast or not fast.next: return False 
			slow = slow.next
			fast = fast.next.next 		
		return True   	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jianafeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值