编程题思路2

动态规划

1递归+记忆化 ->递推

2状态的定义  opt[n] dp[n]  fib[n]

3状态转移方程  opt[n] = best_of(opt[n-1],opt[n-2],.....)

4最优子结构  

 

比如斐波那契数列  N^2时间复杂度

int fib(int n){

return n<=1? n: fib(n-1)+fib(n-2);}

 

现在加入记忆化,增加缓存

F[0]=0,F[1]=1;

for (int i=0;i<=n;++i){

F[i]=F[i-1]+F[i-2];}

 

 

下面一道路径判断题

最后起点到终点,递推  10+17=27种

时间复杂度 O(M*N)

状态方程

opt[i,j]=opt[i-1,j]+opt[i,j-1]

if  a[i,j]= "空地":

    opt[i,j]=opt[i-1,j]+opt[i,j-1]

else: //石头

    opt[i,j]=0

 

DP 回溯  贪心的区别

回溯(递归)  重复计算

贪心 永远局部最后

DP(动态规划,递推) 记录局部最优子结构/多种记录值

 

习题:

1爬楼梯,N层一共几种办法

public int climb(int n){
    if(n==0||n==1||n==2){return n;}
    int[] mem=new int[n];
    mem[0]=1;
    mem[1]=2;
    for(int i =2;i<n;i++){
        mem[i]=mem[i-1] +mem[i-2];
    }
    return mem[n-1];
}

PYTHON

def climb(self,n):
    x,y=1,1
    for _ in range(1,n):
        x,y=y,x+y
    return y

2 三角型最小路径和

 

DP[i,j]=min(DP[i+1,j],DP[i+1,j+1])+Triangle[i,j]

DP[m-1,j]=Triangle[m-1,j]

O(M*N)

   //C++

 class solution{
    public:
        int mininumTotal(vector<vector<int>> &triangle)
        {
            vector<int> mini=triangle[triangle.size()-1];
            for (int i=triangle.size()-2;i>=0;--i)
                for (int j=0;j<triangle[i].size();++j)
                    mini[j]=triangle[i][j] +min(mini[j],mini[j+1]);
            return mini[0];
        }
    };

PYTHON

def mininumTotal(self,n):
    if not triangle: return 0
    res =triangle[-1]
    for i in xrange(len(triangle)-2,-1,-1):
        for j in xrange(len(triangle[i])):
            res[j]=min(res[j],res[j+1])+triangle[i][j]
    return res[0]
 

5乘积最大子序列

class maxproduct:
    def maxproduct(self,nums):
        if nums is None:return 0
        dp =[[0 for _ in range(2)] for _ in range(2)]
        dp[0][0],dp[0][1],res =nums[0],nums[0],nums[0]

        for i in range(1,len(nums)):
            x,y=i%2,(i-1)%2
            dp[x][0]=max(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
            dp[x][1]=min(dp[y][0]*nums[i],dp[y][1]*nums[i],nums[i])
            res=max(res,dp[x][0])
        return res
A=maxproduct()
print(A.maxproduct([1,2,3,4,-1,-2]))
class maxproduct:
    def maxproduct(self,nums):
        if nums is None:return 0
        curMax,curMin,res =nums[0],nums[0],nums[0]

        for i in range(1,len(nums)):
            num=nums[i]
            curMax,curMin=curMax *num,curMin*num
            curMax,curMin=max(curMax,curMin,num),min(curMax,curMin,num)
            res=curMax if curMax>res else res
        return res
A=maxproduct()
print(A.maxproduct([1,2,3,4,-1,-2]))

2股票问题

 


class gupiao:
    def maxProfit(self,prices):
        if not prices:return 0
        res=0
        profit=[[0 for _ in range(3)] for _ in range(len(prices))]
        profit[0][0],profit[0][1],profit[0][2]=0,-prices[0],0
// 第二位状态分别是  没有买入股票  买入一股还没卖  买入一股卖了
        for i in range(1,len(prices)):
            profit[i][0]=prices[i-1][0]  //前一天的状态
            profit[i][1]=max(profit[i-1][1],profit[i-1][0]-prices[i])  //前一天买的今天不动或者今天买入
            profit[i][2]=profit[i-1][1]+prices[i]     //套现
            res=max(res,profit[i][0],profit[i][1],profit[i][2])
        return res

 

 

最长上升子序列

暴力法 2^n

DP  n^2

二分法nlogn

DP法

public int lengthLIS(int[] nums){
if (nums ==null || nums.length ==0){
    return 0;
}
int res =1;
int[] dp=new int[nums.length +1];
for (int i=0;i<nums.length;i++) dp[i]=1;

for(int i=1;i< nums.length;++i){
    for (int j =0;j<nums.length;++i){
        if (nums[j]<nums[i]){
            dp[i]=Math.max(dp[i],dp[j]+1);
        }
    }
    res=Math.max(res,dp[i]);
}
    return res;
}

 

二分法

int lengthLIS(vector<int>& nums){
    vector<int> res;
    for (int i=0;i<nums.size();i++){

//C++中的二分查找 lower_bound 找到最小的比nums[i]大的数
        auto it =std::lower_bound(res.begin(),res.end(),nums[i]);
        if(it==res.end())
            res.push_back(nums[i]);//增加数组元素
        else *it = nums[i]; //替换
    }
    return res.size();
}

 

零钱兑换

比如面值[1,2,5]  拼成11  

贪心:每次选满最大面值

DP:看成上台阶,每次最少的步数

int coinChange(vector<int>& coins, int amount){
    int Max=amount+1;
    vector<int> dp(amount+1,Max);
    dp[0]=0;
    for (int i=1;i<=amount;i++){
        for(int j=0;j<coins.size();j++){
            if (coins[j]<=i){
                dp[i]=min(dp[i],dp[i-coins[j]]+1);
            }
        }

    }
    return dp[amount]>amount ? -1:dp[amount];
}

编辑距离

两个单词,单词1变为单词2,最少需要多少操作

horse -> ros  只用插入删除替换

1暴力法 BFS广度优先

2DP  两部曲   

a 状态  dp[i][j]

i表示单词1  前i个字符,j表示单词2前j个字符

单词1 前i个字符 它匹配单词2前j个字符

结果DP[m][n] 变动次数

bDP方程

DP[i][j]=

for  i 0->m

  for  j  0->n

if w1[i]==w2[j]

  DP[i][j]=DP[i-1][j-1]

else: // 插 删 替

  DP[i][j]=Min(DP[i-1][j],DP[i][j-1],DP[i-1][j-1])+1

def minDistance(self,word1,word2):
    m,n=len(word1),len(word2)
    dp=[[o for _ in range(n+1)] for _ in range(m+1)]

    for i in range(m+1):dp[i][0]=i
    for j in range(m+1):dp[0][j]=j

    for i in range(1,m+1):
        for j in range(1,n+1):
            dp[i][j]=min(dp[i-1][j-1] + (0 if word1[i-1] == word2[j-1] else 1),
                        dp[i-1][j]+1,
                        dp[i][j-1]+1)
    return dp[m][n]

 

并查集

find 确定元素属于哪一个子集

union 将两个子集合并成同一个集合

 

经常解决的问题

1 小弟-》老大

2帮派识别

3两种优化方法  合并&路径压缩

 

岛屿个数  

 

朋友圈

 

 

Cache缓存

记忆

钱包-存储柜

代码模块

 

class LRU(object):
    def __init__(self,capacity):
        self.dic=collections.OrderedDict()
        self.remain=capacity
    def get(self,key):
        if key not in self.dic:
            return -1
        v=self.dic.pop(key)
        self.dic[key]=v
        return v
    def put(self,key,value):
        if key in self.dic:
            self.dic.pop(key)
        else:
            if self.remain >0:
                self.remain -=1
            else:
                self.dic.popitem(last=False)
            self.dic[key]=value

 

布隆过滤器

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值