300. 最长上升子序列
题目:给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入:[10,9,2,5,3,7,101,18]
输出:4
解释:最长的上升子序列是[2,3,7,101]。
思路:动态规划
dp[i]表示以当前元素结尾的子序列的最长长度。
dp[i] = max(dp[j]) + 1 (nums[i] > nums[j])
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
dp = []
for i in range(len(nums)):
if i == 0:
dp.append(1)
else:
t = 0
#找到前面比当前元素小,且长度最长的元素
for j in range(i):
if nums[j] < nums[i] and dp[j] > t:
t = dp[j]
#将当前元素加入到找到的元素后面,长度加1
dp.append(t+1)
return max(dp)
优化:排序 + 二分算法
在找前面比当前元素小且长度最长的子序列时,可以通过结合排序列表,二分查找来提升效率。
面试题01.07 旋转矩阵
给定一幅由N*N矩阵表示的图像,编写一种方法,将图像旋转90度。
不占用额外内存空间能否做到?
示例:
给定 matrix 为左边,原地旋转输入矩阵,使其变为右边:
始:[[1,2,3], 终:[[7,4,1],
[4,5,6], [8,5,2],
[7,8,9]] [9,6,3]]
思路:绕圈旋转
首先,确定旋转的圈数为N/2,即可将矩阵分为N/2圈。
其次,确定每一圈旋转的次数为该圈的边长减1。
每次旋转的时候将四个元素互换位置即可。
每次旋转的四个元素为四个角向对应方向移动j位。
class Solution(object):
def rotate(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: None Do not return anything, modify matrix in-place instead.
"""
length = len(matrix) - 1
i = 0
while i < len(matrix)/2:
for j in range(length):
matrix[i][i+j], matrix[i+j][i+length],matrix[i+length][i+length-j], matrix[i+length-j][i] = matrix[i+length-j][i],matrix[i][i+j], matrix[i+j][i+length],matrix[i+length][i+length-j]
length -= 2
i += 1
面试题16.26 计算器
给定一个包含正整数、加、减、乘、除的算术表达式(括号除外),计算其结果。
表达式仅包含非负整数,+, -, *, /四种运算符和空格 。整数出发仅保留整数部分。
思路:
初始lis =[],存储操作数;初始stack1=[],存储整数;初始stack2=[],存储运算符;
1.整理字符串,将字符串中的整数和运算符部分挑出来,并将整数转换成int类型。
2.用栈来模拟运算,先算乘除,再算加减。
扫描列表,遇到整数进栈stack1,遇到乘或除号,将stack1栈顶出栈与下一个整数运算,然后进栈stack1。
需要注意的是,计算加减时要从左到右运算,即应该从stack1栈底向上扫描。
class Solution(object):
def calculate(self, s):
"""
:type s: str
:rtype: int
"""
multi_1 = ['+','-']
multi_2 = ['*','/']
lis = []
i = 0
while i < len(s):
t = i
while '0' <= s[i] <= '9' and i < len(s)-1:
i += 1
if s[t] != ' ':
if s[t] in multi_2 + multi_1:
lis.append(s[t])
else:
if '0' <= s[i] <= '9' and i != t:
lis.append(s[t:i+1])
break
else:
if i != t:
lis.append(s[t:i])
if s[i] != ' ':
lis.append(s[i])
i += 1
for i in range(len(lis)):
if lis[i] not in multi_2 + multi_1:
lis[i] = int(lis[i])
stack_1 = []
stack_2 = []
i = 0
while i < len(lis):
if lis[i] != '' and lis[i] not in multi_1 + multi_2:
stack_1.append(lis[i])
if lis[i] in multi_1:
stack_2.append(lis[i])
if lis[i] in multi_2:
if lis[i] == '*':
x = stack_1.pop()
x *= lis[i+1]
stack_1.append(x)
if lis[i] == '/':
x = stack_1.pop()
x /= lis[i+1]
stack_1.append(x)
i += 1
i += 1
stack_1 = stack_1[::-1]
stack_2 = stack_2[::-1]
while len(stack_1) > 1:
z = stack_2.pop()
x = stack_1.pop()
y = stack_1.pop()
if z == '+':
stack_1.append(x+y)
if z == '-':
stack_1.append(x-y)
return stack_1[0]
面试题08.11 硬币
硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。结果模上10**9+7。
示例:
输入: n = 5
输出:2
解释:5 = 5, 5 = 1 + 1 + 1 + 1 + 1;这两种表示法。
思路:二维动态规划
这里硬币分为4种,coins = [1, 5, 10, 25]
分四遍扫描,每一遍代表当前n分由前i中表示的方法数目。
dp[j]表示,j分由前i种硬币表示的方法数。
dp[j] += dp[j-coins[i]]
class Solution(object):
def waysToChange(self, n):
"""
:type n: int
:rtype: int
"""
lis = []
coins = [1,5,10,25]
#前两轮分别表示,只由1分和由1分、五分的表示方法
for i in range(n+1):
lis.append(1 + i/5)
for i in range(2,4):
for j in range(n+1):
if j >= coins[i]:
lis[j] += lis[j-coins[i]]
return lis[-1] % (10**9+7)