牛客刷题day3(数组相加和为零的三元组,最长递增子序列,不相邻最大子序和,两个链表的公共节点,设计GetMin功能的栈,大数加法)

牛客刷题day3

1.数组相加和为零的三元组

题目

给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
注意:
三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
解集中不能包含重复的三元组。
例如,给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, 0, 10) (-10, -10, 20)

解题思路

(1)首先对数组进行排序(从小到大)
(2)依次取出第 i 个数(i从0开始),并且不重复的选取(跳过重复的数)
(3)这样问题就转换为 2 个数求和的问题(可以用双指针解决方法)
(4)定义两个指针:左指针(left) 和 右指针(right)
(5)此时left所指的位置为数组中最小数,右指针(right)指向数组中最大数,左指针向后移动,右指针向前移动,找出三数和为0的左右指针的数值
(6)left<right 继续调整 left ,right的位置

核心代码
class Solution:
    def threeSum(self, num):
        # write code here
        res = []
        if not num or len(num) < 3:
            return res
        num.sort()
        n=len(num)-2
        for i in range(n):
            if num[i] > 0:
                break
            if i > 0 and num[i] == num[i - 1]:
                continue
            left = i + 1
            right = len(num) - 1
            while left < right:
                sum = num[i] + num[left] + num[right]
                if sum == 0:
                    res.append([num[i],num[left],num[right]])
                    left+=1
                    right-=1
                    while left < right and num[left] == num[left-1]:
                        left += 1
                    while left < right and num[right] == num[right+1]:
                        right -= 1
                elif sum > 0:
                    right -= 1
                elif sum < 0:
                    left += 1
        return res

2.最长递增子序列

题目

给定数组arr,设长度为n,输出arr的最长递增子序列。(如果有多个答案,请输出其中字典序最小的)
输入:[2,1,5,3,6,4,8,9,7]
输出: [1,3,4,8,9]

解题思路

1.我们用dp[i]表示数组的前i个元素构成的最长上升子序列,如果要求dp[i],我们需要用num[i]和前面的数字一个个比较,如果比前面的任何一个数字大,说明加入到他的后面可以构成一个上升子序列 ,就更新dp[i]。我们就以[8,2,3,1,4]为例来画个图看一下
在这里插入图片描述

核心代码
import bisect
class Solution:
    def LIS(self , arr):
        # write code here
        vec, maxlen = [arr[0]], [1]
        for i in range(1, len(arr)):
            if arr[i]>vec[-1]:
                vec.append(arr[i])
                maxlen.append(len(vec))
            else:
                index = bisect.bisect_left(vec, arr[i])
                vec[index] = arr[i]
                maxlen.append(index+1)
        length = len(vec)
        for i in range(len(arr)-1, -1, -1):
            if maxlen[i] == length:
                length -= 1
                vec[length] = arr[i]
        return vec

3.不相邻最大子序和

题目

给你一个n,和一个长度为n的数组,在不同时选位置相邻的两个数的基础上,求该序列的最大子序列和(挑选出的子序列可以为空)。
3,[1,2,3]
有[],[1],[2],[3],[1,3] 4种选取方式其中[1,3]选取最优,答案为4

解题思路

题目要求是不相邻的子序列值。 什么样子会帮助满足最大呢?
1,序列包含尽可能多的数
2,序列包含尽可能大的数。
考虑不相邻的话,要不要加入第i个数,需要考虑的问题是它前一个i-1 要不要加入,至于i-2则不需要考虑,因为加入第i个数必然可以加入不相邻的i-2 。

核心代码
class Solution:
    def subsequence(self, n, array):
        # write code here
        a, b = 0, 0
        max_arr = 0
        for arr in array:
            max_arr = max(a + arr, b)
            a = b
            b = max_arr
        return max_arr
        

4.两个链表的公共节点

题目

输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

解题思路

首先我们要知道什么是公共节点,两个链表从某一节点开始,他们的next都指向同一个节点。但由于是单向链表的节点,每个节点只有一个next,因此从第一个公共节点开始,之后他们的所有节点都是重合的,不可能再出现分叉。所以可以先遍历两个链表得到他们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个结点。在第二次遍历的时候,在较长的链表上先走若干步,接着同时在两个链表上遍历,找到的第一个相同的结点就是他们的第一个公共结点

核心代码
class Solution:
    def FindFirstCommonNode(self , pHead1 , pHead2 ):
        # write code her
        p1,p2 =pHead1,pHead2
        while p1!=p2:
            if p1:
                p1=p1.next
            else:
                p1=pHead2
            if p2:
                p2=p2.next
            else:
                p2=pHead1
        return p1
        

5.设计GetMin功能的栈

题目

实现一个特殊功能的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。
有三种操作种类,op1表示push,op2表示pop,op3表示getMin。你需要返回和op3出现次数一样多的数组,表示每次getMin的答案
输入:[[1,3],[1,2],[1,1],[3],[2],[3]]
返回:[1,2]

思路

在这里插入图片描述

核心代码
class Solution:
    def getMinStack(self, op):
        # write code here
        stack1 = []
        stack2 = []
        res = []
        for item in op:
            if item[0] == 1:
                stack1.append(item[1])
            if item[0] == 2:
                stack1.pop()
            if item[0] == 3:
                res.append(min(stack1))
        return res
          

6.大数加法

题目

以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。(字符串长度不大于100000,保证字符串仅由’0’~'9’这10种字符组成)

解题思路

1.maxlen是较长的字符串
2.用zfill()对短的字符串填充0,使用ord()将字符串转为数字进行计算
3.从个位开始相加,plus保存的进位,rest保存是相加的个位数
4.最后得到的字符串翻转即是答案

使用python需要使用zfill()方法,其主要作用是用来返回指定长度的字符串,原字符串右对齐,前面填充0。具体用法见python zfill()
还需要用到 ord() 函数 :ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。python ord()

核心代码
class Solution:
    def solve(self , s , t ):
        # write code here
        maxlen = max(len(s), len(t))
        s = s.zfill(maxlen)
        t = t.zfill(maxlen)
        plus = 0
        rest = ''
        for i in range(-1, -maxlen -1, -1):
            last = ord(s[i]) + ord(t[i]) + plus - 96
            rest += str(last % 10)
            plus = last // 10
        if plus != 0:
            rest += str(plus)
        return rest[::-1]

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值