二维数组中的查找(简单)
题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
分治解题思路
- 从右上角(或者左下角)开始查找
- 如果target更大,指针下移
- 如果target更小,指针左移
运行时间:249ms
占用内存:5708k
class Solution:
def Find(self, target, array):
i=0
j=len(array[0])-1
while i<len(array) and j>=0:
base=array[i][j] #和右上角数字比较
if target==base:
return True
elif target>base:#下移
i+=1
else:#左移
j-=1
return False
替换空格(简单)
题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路
先遍历找到多少个空格,然后开辟数组填充
- 先遍历找到所有空格数
- 计算新开辟数组大小
- 初始化新数组
- 字符串为空的位置填充“%20",索引前进
- 不为空的地方把原来的字母填上去,索引前进
- 返回新字符串
运行时间:23ms
占用内存:5860k
class Solution:
# s 源字符串
def replaceSpace(self, s):
# write code here
# s_len=len(s)
space_count=0
for i in range(len(s)):
if s[i]==' ':
space_count+=1
new_len=len(s)+(3*space_count)
new_array=['']*new_len
j=0
for i in range(len(s)):
if s[i]==' ':
new_array[j]='%'
new_array[j+1]='2'
new_array[j+2]='0'
j+=3
else:
new_array[j]=s[i]
j+=1
return ''.join(new_array)
从尾到头打印链表(简单)
题目描述
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路
用栈存放,再输出
- 给一个栈
- 给一个放结果的数组
- 复制链表指针
- 当链表指针不为空时,继续取值
- 将链表的值放入栈中
- 指针前进
- 然后从栈中往出取值
- 取值pop(-1)放入结果数组里
- 返回结果
运行时间:35ms
占用内存:5856k
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回从尾部到头部的列表值序列,例如[1,2,3]
def printListFromTailToHead(self, listNode):
# write code here
stack=[]
result=[]
node_p=listNode
while node_p:
stack.append(node_p.val)
node_p=node_p.next
while stack:
result.append(stack.pop(-1))
return result
重建二叉树(中等)
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路
用前序遍历找到根结点,用根结点在中序遍历中切开左右子树,递归重建二叉树
- 前序数组为空时,返回空
- 用前序遍历找到根结点
- 初始化一个为根值的树节点
- 遍历后序数组,找到根数值的索引位置i
- 切分左右子树,递归调用本函数
- 返回根节点
运行时间:42ms
占用内存:5724k
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回构造的TreeNode根节点
def reConstructBinaryTree(self, pre, tin):
# write code here
if not pre:
return
root_val=pre[0]
root=TreeNode(root_val)
for i in range(len(tin)):
if tin[i]==root_val:break
root.left=self.reConstructBinaryTree(pre[1:1+i],tin[:i])
root.right=self.reConstructBinaryTree(pre[1+i:],tin[i+1:])
return root
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
用两个栈实现队列(中等)
题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路
队列先进先出,栈先进后出
栈1负责添加,而栈2负责删除
添加:
压入栈1
删除:
当栈2为空时:把栈1逐个弹入栈2,栈2栈顶pop
当栈2不为空时:将栈2栈顶pop
运行时间:38ms
占用内存:5700k
class Solution:
def __init__(self):
self.stack1=[]
self.stack2=[]
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
if not self.stack2:
while self.stack1:
self. stack2.append(self.stack1.pop(-1))
return self.stack2.pop(-1)
旋转数组的最小数字(中等?)
题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路
输入一个非递减排序的数组,就是说这个数组是个递增数组
总体二分:
- if mid大于left, left = mid
- if mid小于left, right = mid
- 直到mid<mid-1位置的数
不知道为什么 牛客网未AC
class Solution:
def minNumberInRotateArray(self, rotateArray):
# write code here
if not rotateArray:
return 0
low=0
high=len(rotateArray)-1
while True:
mid = (low + high)>>1
if rotateArray[mid]>=rotateArray[low]:
low=mid
else:
high=mid
if rotateArray[mid]<rotateArray[mid-1]:
return rotateArray[mid]
斐波那契数列(简单)
题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39
运行时间:24ms
占用内存:5728k
class Solution:
def Fibonacci(self, n):
# write code here
f1=0
f2=1
if n==0:return f1
elif n==1:return f2
for _ in range(n-1):
temp=f1+f2
f1=f2
f2=temp
return f2
跳台阶(执行简单,思路复杂)
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
思路
假设对于第n级台阶,总共有f(n)种跳法.
那么f(n) = f(n-1) + f(n-2),其中f(1)=1,f(2)=2
运行时间:26ms
占用内存:5852k
class Solution:
def jumpFloor(self, number):
f1=1
f2=2
if number==1:return f1
elif number==2:return f2
for _ in range(number-2):
f2,f1=f1+f2,f2
return f2
二进制中1的个数(执行复杂,思路不简单)
题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路
如果n!=0,n的二进制中至少有一个1
- 如果1在最低位, n&(n-1) 得到的数正好…??
- 如果1不在最低位, n&(n-1) 得到的数正好…??
因此我们判断 n&(n-1) 能够循环运行的次数就可以判断二进制中有多少个1
在python中需要使用 n&(n-1) 函数不然负数不会变成0.
运行时间:35ms
占用内存:5696k
from ctypes import c_int
class Solution:
def NumberOf1(self, n):
# write code here
cnt=0
while c_int(n).value:
n=n&(n-1)
cnt+=1
return cnt
数值的整数次方(中等)
题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
思路
保证base和exponent不同时为0
指数幂的所有边界包括:
- 指数为0的情况,不管底数是多少都应该是1
- 指数为负数的情况,求出的应该是其倒数幂的倒数
- 指数为负数的情况下,底数不能为0
涉及知识点:位运算 数学
调整数组顺序使奇数位于偶数前面(简单)
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路
- 初始化个与原数组的等长的新数组
- 遍历数组,计算奇数个数
- 前半部分是奇数的坑,后半部分是偶数的坑,所以偶数索引从奇数个数后面开始算
- 遍历数组。为奇数时,填坑,索引前进 。为偶数时,填坑,索引前进 返回新数组
运行时间:23ms
占用内存:5728k
class Solution:
def reOrderArray(self, array):
# write code here
res=len(array)*[0]
odd_cnt=0
for i in range(len(array)):
if array[i]%2 != 0:
odd_cnt+=1
odd_i=0
edd_i=odd_cnt
for i in range(len(array)):
if array[i]%2!=0:
res[odd_i]=array[i]
odd_i+=1
else:
res[edd_i]=array[i]
edd_i+=1
return res
链表中倒数第k个结点(实现简单,思路清爽)
题目描述
输入一个链表,输出该链表中倒数第k个结点。
思路
快慢指针
fast_p比slow_p快k步,当fast_p到链表尾巴的时候,slow_p刚好是倒数第k个节点
- 链表为空时,返回空
- 初始化快慢指针都为头指针
- 开始快指针先走,定位快指针为第k个点,
- k步的循环完了,快指针就比慢指针,快k步了
- k步没走完就到头了,说明该链表没有倒数第k个点,长度不够,返回空
- 快指针没有到尾巴,就继续走
- 快指针走走走 慢指针走走走
- 快指针到尾巴了,跳出循环,返回慢指针
运行时间:28ms
占用内存:5728k
class Solution:
def FindKthToTail(self, head, k):
# write code here
if not head:return None
fast_p=head
slow_p=head
for _ in range(k):
if fast_p:
fast_p=fast_p.next
else:
return None
while fast_p:
fast_p=fast_p.next
slow_p=slow_p.next
return slow_p
反转链表(非递归版本,思路再消化!)
题目描述
输入一个链表,反转链表后,输出新链表的表头。
思路
用三个指针,分别指向prev,cur 和 nxt,然后loop一圈还算比较简单.
重点消化这几句:
while cur:
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
运行时间:30ms
占用内存:5756k
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
prev = None
cur = pHead
while cur:
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
return prev
合并两个排序的链表(思路简单,操作麻烦)
题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
LeetCode 通过
牛客网未AC
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
result=[]
if pHead1.val<=pHead2.val:
res=pHead1
result.append(pHead1.val)
pHead1=pHead1.next
else:
res=pHead2
result.append(pHead2.val)
pHead2=pHead2.next
head=res
while pHead1 and pHead2:
if pHead1.val<=pHead2.val:
head.next=pHead1
result.append(pHead1.val)
head = head.next
pHead1=pHead1.next
else:
head.next=pHead2
result.append(pHead2.val)
head = head.next
pHead2=pHead2.next
if pHead1:
head.next=pHead1
if pHead2:
head.next=pHead2
while head:
result.append(head.val)
head=head.next
return result
顺时针打印矩阵(细心)
题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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.
思路
- 初始化一个行列数均多1的布尔矩阵,作为标记矩阵,值全为false
- 将最后一行和最后一列标记为True,为边缘做防护,两个循环搞定
- 两个常量标记矩阵行列数 两个变量标记走的位置 来个放结果的数组 还需要一个定位方向的变量,一开始向右走
- 循环:该位置标志为false,意味着没走过,则进入while循环
加入结果数组 走过,所以标记为true
向右走:如果索引可走且未到右边缘,索引前进
否则:往右走到头了,往下走,索引前进
向下走:如果索引可走且未到下边缘,索引前进
否则:往下走到头了,往上走,索引前进
向左走:如果索引可走且未到边缘,索引前进
否则:往左走到头了,往上走,索引前进
向上走:如果索引可走且未到边缘,索引前进
否则:往右走到头了,往右走,索引前进
运行时间:25ms
占用内存:5720k
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
walked = [[False] * (len(matrix[0])+1) for _ in range(len(matrix)+1)]
for j in range(len(walked[-1])):
walked[-1][j] = True
#print walked
for i in range(len(walked)):
walked[i][-1] = True
len_row = len(matrix) - 1
len_col = len(matrix[0]) - 1
res = []
i = 0
j = 0
direction = 0 #
#print walked
while not walked[i][j]:
# print walked
res.append(matrix[i][j])
walked[i][j] = True
if direction == 0: # right
if j < len_col and not walked[i][j+1]:
j += 1
else:
direction = 1
i += 1
elif direction == 1: # down
if i < len_row and not walked[i+1][j]:
i += 1
else:
direction = 2
j -= 1
elif direction == 2: # left
if j > 0 and not walked[i][j-1]:
j -= 1
else:
direction = 3
i -= 1
elif direction == 3: # up
if i > 0 and not walked[i-1][j]:
i -= 1
else:
direction = 0
j += 1
return res
包含min函数的栈(简单)
题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路
用辅助栈(和原栈等长的)存储当前data的最小值,辅助栈头即为min值。
运行时间:25ms
占用内存:6256k
- 初始化一个空栈
- 初始化一个最小栈,栈头是最小值(和原栈等长)
- push(self, node):
给栈添加新的值
如果最小栈里没有值,就把该值放入最小栈
如果最小栈里有值
且最小栈的最小值小于当前值 则加一个最小值给最小栈
否则,最小栈的最小值大于当前值,则把当前值放入最小栈 - top(self):返回栈顶值,但不删除栈顶值
class Solution:
def __init__(self):
self.stack=[]
self.min_stack=[]
def push(self, node):
# write code here
self.stack.append(node)
if not self.min_stack:
self.min_stack.append(node)
else:
if self.min_stack[-1]<node:
self.min_stack.append(self.min_stack[-1])
else:
self.min_stack.append(node)
def pop(self):
# write code here
self.min_stack.pop(-1)
return self.stack.pop(-1)
def top(self):
# write code here
if self.stack:
return self.stack[-1]
else:
return
def min(self):
# write code here
return self.min_stack[-1]
栈的压入、弹出序列(简单)
题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
思路
遍历压入栈,存储于栈中,遍历过程中,如果栈顶是出栈结点,推出值。
- 最终栈空则弹出序列有效
- 栈不空则弹出序列无效
- 初始化一个stack数组 弹出栈索引i
- 遍历压入栈
- 每个值添加进stack数组
当stack数组非空且末尾值=弹出栈栈顶值时
弹出栈索引前进
stack数组删除最后末尾值 - 若stack为空(说明压入栈已经遍历完了,stack也弹出完了):返回真
若stack不为空(说明压入栈已经遍历完了,stack没有弹出完):返回假
运行时间:30ms
占用内存:8448k
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
stack=[]
i=0
for v in pushV:
stack.append(v)
while stack and stack[-1]==popV[i]:
i+=1
stack.pop(-1)
if not stack :
return True
else:
return False
字符串的排列(很重要,见过多次)
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
思路
取出第i个数,全排列其他非i位置的数拼在后面。
- 只有一个字母时,返回他自己
- 给我个数组放结果
- for循环遍历,取出除去第i个数的其他数进行全排列(递归)
- for循环遍历返回结果,其他非i位置的数拼在后面。(res.append(s[i] + j))
去重,排序,怎么不用这两个函数 sorted(list(set(res))) 解决重复和顺序问题
class Solution:
def helper(self,s):
if len(s)==1:return s[0]
res=[]
for i in range(len(s)):
temps=self.helper(s[:i]+s[i+1:])
for j in temps:
if j not in res:
res.append(s[i] + j)
res=sorted(list(set(res)))#去重,排序
return res
def Permutation(self, ss):
# write code here
if not ss:return []
wordslist=list(ss)
return self.helper(ss)
数组中出现次数超过一半的数字(思路清奇又清爽)
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路
从我们之前的那道超过一半的数来入手,我们的"阵地攻守"的解法是每遇到2个不同的数,就删除,剩下的就是那个出现次数超过一半的数字。
于是"阵地攻守"中每次不同的元素就删除(同归于尽)
放暂存值
作为抵消值
遍历数组
如果暂存值不存在
当前值复制给暂存值
抵消值设为1
如果暂存值存在
若当前值==暂存值
抵消值加一
若当前值!=暂存值
抵消值-1
若前面的两两不同值都已经彼此抵消
暂存值设为初值0
记住上面这个没抵消完的暂存值出现的次数,一次循环搞定
再次验证下
运行时间:25ms
占用内存:5736k
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
res=None
cnt=0
for i in numbers:
if not res:
res=i
cnt=1
else:
if res==i:
cnt+=1
else:
cnt-=1
if cnt==0:
res=None
count=0
for i in numbers:
if i==res:
count+=1
if count>(len(numbers)//2):
return res
else:return 0
最小的K个数(建堆麻烦)
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路
思路1:
- 最小堆建立(需要o(n)时间复杂度)
- 取出前k个数(每次取需要用logn时间重建堆)。时间复杂度为o(n)+o(k*logn)
堆的定义:具有n个元素的序列,位置k的结点的父结点的位置为k/2 向下取整,而他的两个子结点的位置分别为2k和2k+1.
运行时间:26ms
占用内存:5624k
思路2:
- 用快排partition划分,一直划中第k个数 最差情况o(kn)
class Solution:
def sink(self,array,k):
length=len(array)
left=2*k+1
right=2*k+2
if left >= length: return
min_i=left
if right<length and array[left]>array[right]:
min_i=right
if array[min_i]<array[k]:
array[min_i],array[k]=array[k],array[min_i]
self.sink(array,min_i)
def build_heap(self,array):
length=len(array)
for i in range(length//2,-1,-1):
self.sink(array,i)
return array
def GetLeastNumbers_Solution(self, tinput, k):
# write code here
if k>len(tinput):return []
heap=self.build_heap(tinput)
res=[]
for _ in range(k):
heap[0],heap[-1]=heap[-1],heap[0]
res.append(heap.pop())
self.sink(heap,0)
return res
连续子数组的最大和
题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路1, 动态规划:
dp[i] = dp[i-1] + p[i] # if i != 0 and dp[i-1] > 0
dp[i] = p[i] # if i == 0 or dp[i-1] < 0