常规手撕题目:
题目一:01背包问题(dp)
给两个数组,w[2,3,5,10]表示每个物品的大小,v[4,1,8,3]表示每个物品对应的价值,然后给一个背包的大小s,然后问能装下的最多的价值。
解题:利用动归,构建一个dp数组,并初始化;
dp数组的改变情况:(1)j< w [i] :那么dp[i][j]=dp[i-1][j];(2)j>=w[i] :那么dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
w=[9,2,1]
v=[1,4,9]
s=10
w.insert(0,0)
v.insert(0,0)
dp=[[0 for _ in range(s+1)] for _ in range(len(w))]
for i in range(1,len(w)):
for j in range(1,s+1):
if j<w[i]:
dp[i][j]=dp[i-1][j]
else:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
print(dp[-1][-1])
题目二:寻找路径(dfs),可以上下左右
给一个矩阵,寻找是否存在一条路径满足题意;
解题:采用dfs的方式,遍历数组的每个元素,然后dfs,dfs中上下左右移动,并加入一个矩阵标记是否访问过,判断是否满足条件,其中条件有
(1)超过边界;
(2)已经访问过;
(3)不等于所要找的路径元素;
附上代码:
class Solution {
int d[4][4]={{-1,0},{1,0},{0,-1},{0,1}};
int rows;
int cols;
bool inArea(int x,int y)
{
if(x<0 || x>=rows || y<0 || y>=cols)
return false;
else
return true;
}
bool dfs(vector<vector<char>>& b,string w,vector<vector<char>>& v,int x,int y,int index)
{
if(index==w.length()-1)
return w[index]==b[x][y];
if(b[x][y]==w[index])
{
v[x][y]=true;
for(int i=0;i<4;i++)
{
int newx=x+d[i][0];
int newy=y+d[i][1];
if(inArea(newx,newy)&&!v[newx][newy])
{
bool res=dfs(b,w,v,newx,newy,index+1);
if(res)
return true;
}
}
v[x][y]=false;
}
return false;
}
public:
bool exist(vector<vector<char>>& board, string word) {
rows=board.size();
if(rows==0)
return false;
cols=board[0].size();
if(cols==0)
return false;
vector<vector<char>> visit(rows,vector<char>(cols,false));
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
bool res=dfs(board,word,visit,i,j,0);
if(res)
return true;
}
}
return false;
}
};
问题三:爬楼梯问题(dp)
一次可以爬一阶或者两阶,那么n阶台阶有几种方式到达。
解题:采用动态规划求解
1、确认原问题和子问题;
2、确认状态;
3、确认边界情况;dp[1]=1;dp[2]=2;
4、状态转移方程;dp[i]=dp[i-1]+dp[i-2];
附上代码:
def jump(self,n):
dp=[0]*n
if n==1:
return 1
dp[0]=1
if n==2:
return 2
dp[1]=2
for i in range(2,n):
dp[i]=dp[i-1]+dp[i-2]
return dp[n-1]
问题四:小偷(bp)
一个小偷,不连续两家偷盗的情况下,最大的价值
解题:采用动态规划求解
1、确认原问题和子问题;
2、确认状态;
3、确认边界情况;dp[1]=a[0];dp[2]=max(a[0],a[1]);
4、状态转移方程;dp[i]=max(dp[i-1],dp[i-2]+a[i]);
附上代码:
def rob(self,nums):
n=len(nums)
dp=[0]*n
if n==0:
return 0
if n==1:
return nums[0]
dp[0]=nums[0]
if n==2:
return max(nums[0],nums[1])
dp[1]=max(nums[0],nums[1])
for i in range(2,n):
dp[i]=max(dp[i-2]+nums[i],dp[i-1])
return dp[n-1]
问题五:最小的钞票数(dp)
面值为【1、2、5、10】的钞票,求14的组合最少的钞票个数
分析:采用动态规划
1、确认原问题和子问题;
2、确认状态;
3、确认边界情况;dp[0]=0;dp[1]=1];dp[2]=1;
4、状态转移方程;dp[i]=min(dp[i-1],dp[i-2],dp[i-5],dp[i-10])+1
附上代码:
def coins(self,n,cot):
dp=[]
for i in range(cot+1):
dp.append(-1)
dp[0]=0
for i in range(1,cot+1):
for j in range(len(n)):
if i-n[j]>=0 and dp[i-n[j]]!=-1:
if dp[i]==-1 or dp[i]>dp[i-n[j]]+1:
dp[i]=dp[i-n[j]]+1
return dp[cot]
附上方法二代码:
def coin(self,n,cot):
dp=[cot+1]*(cot+1)
dp[0]=0
for i in range(cot+1):
for item in n:
if item>i:
continue
else:
dp[i]=min(dp[i],1+dp[i-item])
if dp[cot]==cot+1:
return -1
else:
return dp[cot]
问题六:快排(递归)和链表快排(双指针)
对于快排,可以采用递归的方式,也可以采用切片的方式;
附上代码:
def fast(self,nums):
res=self.quick(nums,0,len(nums)-1)
return res
def quick(self,nums,start,end):
if start<end:
p=self.position(nums,start,end)
self.quick(nums,start,p-1)
self.quick(nums,p+1,end)
return nums
def position(self,nums,start,end):
base=nums[start]
low,high=start,end
while low<high:
while low<high and nums[high]>=base:
high-=1
nums[low]=nums[high]
while low<high and nums[low]<base:
low+=1
nums[high]=nums[low]
nums[low]=base
return low
def fast2(self,nums):
if len(nums)<=1:
return nums
else:
base=nums[0]
l=[x for x in nums if x<base]
m=[x for x in nums if x==base]
r=[x for x in nums if x>base]
return self.fast2(l)+m+self.fast2(r)
链表快排,只能从头到尾遍历
附上代码:
pNode* partition(pNode* start,pNode* end){
int num = start->val;
pNode* p = start;
pNode* q = start->next;
while(q != end){
if(q->val < num){
p = p->next;
swap(p->val,q->val);
}
q = q->next;
}
swap(p->val,start->val);
return p;
}
void quick_sort(pNode* start,pNode* end){
if(start != end){
pNode* index = partition(start,end);
quick_sort(start,index);
quick_sort(index->next,end);
}
}
问题七:全排列(递归)
给[1,2,3],求出全排列,利用递归思想,python中的切片;
附上代码:
def perm(self,res,nums,temp):
if len(nums)==0:
res.append(temp)
return
for i in range(len(nums)):
self.perm(res,nums[:i]+nums[i+1:],temp+[nums[i]])
问题八:格雷码(数学)
给出n为二进制bit,其中相邻的元素,只有唯一一位bit不同;(00 01 11 10)
附上代码:
def gradCode(self,n):
res=[]
i=0
while i<(1<<n):
res.append(i^(i>>1))
i+=1
return res
问题九:集合的子集(递归)
给一个集合,求子集,去掉重复的子集
附上代码:
def subset(self,nums):
res=[]
temp=[]
nums.sort()
def sub(nums,temp,res,cur):
res.append(temp.copy())
for i in range(cur,len(nums)):
if i>cur and nums[i]==nums[i-1]:
continue
temp.append(nums[i])
sub(nums,temp,res,i+1)
temp.pop()
sub(nums,temp,res,0)
return res