牛客刷题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]