题号均对应牛客网,解法均使用python2.7
输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)
分析:这道题是链表的入门级题目,主要考察链表和列表的基础知识,总结见https://blog.csdn.net/Xiao__Bei/article/details/126729085?spm=1001.2014.3001.5501
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
cur = listNode
res = list()
while cur:
res.append(cur.val)
cur = cur.next
return res[::-1]
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。
1.此题对比原题有改动
2.题目保证链表中节点的值互不相同
3.该题只会输出返回的链表和结果做对比,所以若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
数据范围:
0<=链表节点值<=10000
0<=链表长度<=10000
#coding:utf-8
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @param val int整型
# @return ListNode类
#
class Solution:
def deleteNode(self , head , val ):
# write code here
# 区分是否删除头结点
# 保留删除节点的前一个节点,构造删除函数
# 滑动窗口
# res = head
# if res.val == val:
# res = res.next
# return res
# else:
# cur = res.next
# while cur.next:
# if cur.val == val:
# res.next = cur.next
# break
# else:
# res = cur
# cur = cur.next
# return head
#另一种解法是直接设置一个头结点,这样可以直接判断
if head == None:
return head
res = ListNode(0)
pre = res
pre.next = head
cur = head
while cur:
if cur.val == val:
pre.next = cur.next
break
pre = cur
cur = cur.next
return res.next
给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
#思想是要把当前节点cur的next节点保存下来,因为cur节点指向pre节点后,会找不到下一个节点对的位置
# pre = ListNode()
pre = None
#ListNode()新建一个节点,不赋值
#ListNode(0)新建一个节点,赋值0
#None是NoneType,空
cur = pHead
if pHead == None:
return pHead
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
数据范围: 0 \le n \le 10000≤n≤1000,-1000 \le 节点值 \le 1000−1000≤节点值≤1000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
p1 = pHead1
p2 = pHead2
#建立一个res节点,数据类型是链表节点,值为0,又可以赋值-1
pHead = ListNode(0)
p = pHead
while p1 != None and p2 != None: #且
if p1.val <= p2.val:
p.next = p1
p1 = p1.next
else:
p.next = p2
p2 = p2.next
p = p.next #p指向下一个节点。相当于向后走一步
while p1 != None:
p.next = p1 #p的下一个节点赋值为p1
p = p.next
p1 = p1.next
while p2 != None:
p.next = p2
p = p.next
p2 = p2.next
return pHead.next #注意不是pHead
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
#注意排除相同节点的情况
#两个链表连起来
p1 = pHead1
p2 = pHead2
while p1 != p2:
if p1 != None:
p1 = p1.next
else:
p1 = pHead2
if p2 != None:
p2 = p2.next
else:
p2 = pHead1
return p1
给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null.
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
#双指针
fast = pHead
slow = pHead
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
break
if not fast or not fast.next:
return None #需要额外判断下空链表或者只有没有环的情况
while pHead != slow:
if pHead and slow:
pHead = pHead.next
slow = slow.next
return slow
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param pHead ListNode类
# @param k int整型
# @return ListNode类
#
class Solution:
def FindKthToTail(self , pHead , k ):
# write code here
fast = pHead
slow = pHead
m = 1
while m <= k:
if fast: #避免pHead为空的情况
fast = fast.next
m +=1
else: #避免 k大于链表长度
return None
while fast:
fast = fast.next
slow = slow.next
return slow #输出时,fast位于尾节点的下一个节点,slow位于
# -*- coding:utf-8 -*-
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class Solution:
def deleteDuplication(self, pHead):
# write code here
# 设一个头结点,,保存删除前结点
# write code here
if pHead == None or pHead.next == None:
return pHead
dummy = ListNode(-1) #虚拟头结点
dummy.next = pHead
tail = dummy #真实链表的尾节点
nex = None #nex会根据pHead随时变化,所以在循环外不初始化值
while pHead and pHead.next: #需要增加pHead.next,因为后续有其值的判断
nex = pHead.next
if pHead.val == nex.val:
while nex and nex.val == pHead.val:
nex = nex.next #删除掉重复节点起的第二个节点
tail.next = nex #确定当前尾节点
pHead = nex
else:
tail = pHead #后移尾节点
pHead = pHead.next
return dummy.next #返回已经处理后的真实链表头结点
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1
# -*- coding:utf-8 -*-
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param numbers int整型一维数组
# @return int整型
#
class Solution:
def duplicate(self, numbers):
# write code here
if numbers == None:
return -1
# set去重
res_set = set()
for i in numbers:
if i in res_set:
return i
else:
res_set.add(i)
return -1
'''
用字典
'''
res_dict = collections.Counter(numbers)
for key, val in res_dict.items():
if val > 1:
return key
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
#
# @lc app=leetcode.cn id=34 lang=python3
#
# [34] 在排序数组中查找元素的第一个和最后一个位置
#
# @lc code=start
from typing import List
from unittest import result
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
# 如果直接确定在或不在直接用二分法就可以
result = [-1, -1]
left, right = 0, len(nums) - 1
# tmp = 0
while left <= right:
mid = (left + right) // 2
if nums[mid] > target:
right = mid - 1
elif nums[mid] < target:
left = mid + 1
else:
left = right = mid
while left -1 >= 0:
if nums[left -1] == target:
left -= 1
else:
break # 当满足if条件可使用break退出while循环
while right+1 <= len(nums) -1 and nums[right + 1] == target:
right += 1
return [left, right]
return result
# 暴力解法 ,时间复杂度和空间复杂度都是O(n)
# result = []
# index = 0
# while index <= len(nums)-1:
# if nums[index] == target:
# result.append(index)
# index += 1
# if len(result) == 0:
# return [-1,-1]
# else:
# return [result[0], result[len(result)-1]]
# @lc code=end
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
# -*- coding:utf-8 -*-
class Solution:
# array 二维列表
def Find(self, target, array):
# write code here
if array == None or len(array) == 0:
return False
# 从左下角开始找起,左下角是最小值的最大值,这样查找可以安行排查
row = len(array) #行
col = len(array[0]) #列
left, down = 0, row-1#left和down分别表示行列的移动指针
while left < col and down >= 0:
if array[down][left] == target:
return True
elif array[down][left] < target:
left += 1
else:
down -= 1
return False
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。
# -*- coding:utf-8 -*-
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
#二分查找找到峰值,注意可能有多个连续相等的值
if len(rotateArray) == 0:
return None
left = 0
right = len(rotateArray) -1
while left < right:
mid = (left+right)/2
if rotateArray[mid] > rotateArray[right]:
left = mid+1
elif rotateArray[mid] < rotateArray[right]:
right = mid
else:
right -= 1
return rotateArray[left]
输入一个长度为 n 整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
# -*- coding:utf-8 -*-
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param array int整型一维数组
# @return int整型一维数组
#
class Solution:
def reOrderArray(self, array):
# write code here
# 冒泡排序
for i in range(len(array)):
for j in range(len(array)-1-i):
if array[j] %2 == 0 and array[j+1] %2 == 1:
array[j], array[j+1] = array[j+1], array[j]
return array
"""
暴力解法
left = []
right = []
for i in range(len(array)):
if array[i]%2 == 0:
right.append(array[i])
else:
left.append(array[i])
return left + right
"""
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵:
[[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]]
则依次打印出数字
[1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10]
# -*- coding:utf-8 -*-
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
# python的二维列表可以理解为是[[],[]]的形式,用matrix表示数组的行,matrix[0]表示数组的列
res = []
while matrix:
res += matrix.pop(0)
if not matrix or not matrix[0]:
break
matrix = self.turn(matrix)
return res
def turn(self, matrix):
res_matrix = []
for i in range(len(matrix[0])):
res_tmp = []
for j in range(len(matrix)):
res_tmp.append(matrix[j][i])
res_matrix.append(res_tmp) #appendappend 是将数组以数组的方式加到原来的list中,+ 是将新加入数组的每一个数值加进去,等同于extend
res_matrix.reverse()
return res_matrix
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
# -*- coding:utf-8 -*-
import collections
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
"""
# 候选法
# 思想就是:假如数组中存在众数,那么众数一定大于数组的长度的一半。也就是它的数量一定比其它所有数字之和还要多,按照这个思路得出num,然后验证
"""
if len(numbers) == 0:
return None
num = numbers[0]
count = 1
for i in range(1,len(numbers)):
if numbers[i] == num:
count += 1
else:
count -= 1
if count == 0:
num = numbers[i]
count = 1
# 验证
count = 0
for i in numbers:
if i == num:
count += 1
return num if count > len(numbers)/2 else None
"""
偷懒思想,直接用collections
leng = len(numbers)/2
res_dict = collections.Counter(numbers)
for k, v in res_dict.items():
if v > leng:
return k
return None
"""
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,找到一个具有最大和的连续子数组。
1.子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
2.如果存在多个最大和的连续子数组,那么返回其中长度最长的,该题数据保证这个最长的只存在一个
3.该题定义的子数组的最小长度为1,不存在为空的子数组,即不存在[]是某个数组的子数组
4.返回的数组不计入空间复杂度计算
在这里插入代码片
输入一个非负整数数组numbers,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
例如输入数组[3,32,321],则打印出这三个数字能排成的最小数字为321323。
1.输出结果可能非常大,所以你需要返回一个字符串而不是整数
2.拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0
在这里插入代码片
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007
在这里插入代码片
给定一个长度为 n 的非降序数组和一个非负数整数 k ,要求统计 k 在数组中出现的次数
# -*- coding:utf-8 -*-
class Solution:
def GetNumberOfK(self, data, k):
# write code here
# 看到升序数组立马想到用二分法解决
left, right = 0, len(data)-1
while left <= right:
mid = (left + right) //2
if data[mid] < k:
left = mid + 1
else:
right = mid - 1
l = right
left, right = 0, len(data)-1
while left <= right:
mid = (left + right) //2
if data[mid] <= k:
left = mid + 1
else:
right = mid - 1
r = left
cur = r-l-1
return cur if cur else 0
"""
#双指针法,注意循环终止条件,以及对只有一个值的特殊情况判断
if len(data) == 1:
return 1 if k in data else 0
return 0
left, right = 0, len(data)-1
while left< right:
if data[left] != k:
left += 1
if data[right] != k:
right -= 1
if data[left] == k and data[right] == k:
return (right - left)+1
return 0
"""
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
## -*- coding:utf-8 -*-
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param array int整型一维数组
# @return int整型一维数组
#
#用了set方法,时间复杂度和空间复杂度都是O(n)
class Solution:
def FindNumsAppearOnce(self , array ):
# write code here
res = []
res_set = set()
for i in array:
if i not in res_set:
res_set.add(i)
else:
res_set.remove(i)
for j in res_set:
res.append(j) #直接return j其实也可以,牛客的输出限定了需要是list
return res
给定一个数组 A[0,1,…,n-1] ,请构建一个数组 B[0,1,…,n-1] ,其中 B 的元素 B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1](除 A[i] 以外的全部元素的的乘积)。程序中不能使用除法。(注意:规定 B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2])
# -*- coding:utf-8 -*-
class Solution:
def multiply(self, A):
# write code here
#这道题除了考察两部分积相乘的算法思想外,还考察对for循环的熟练掌握
B = [1 for i in range(len(A))]
for i in range(1,len(A)):
B[i] = B[i-1] * A[i-1]
tmp = 1
for j in reversed(range(len(A))): #倒序遍历[0,len(A)-1],可以用reversed(range())
B[j] *= tmp
tmp *= A[j]
return B
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
#coding:utf-8
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param n int整型 最大位数
# @return int整型一维数组
#
class Solution:
def printNumbers(self , n ):
# write code here
tmp = 1
res = []
for i in range(n):
tmp *= 10
tmp -= 1
for i in range(1, tmp+1):
res.append(i)
return res
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
# -*- coding:utf-8 -*-
#不能用判断和循环语句,需要考虑使用递归
class Solution:
def __init__(self):
self.res = 0
def Sum_Solution(self, n):
# write code here
n > 0 and self.Sum_Solution(n-1)
self.res += n
return self.res
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1 。
在这里插入代码片