動態規划算法java代碼實現


兩個例子,使用動態規划算法解決
第一個例子是LeetCode題目:

面試題 17.16:

按摩師一個有名的按摩師會收到源源不斷的預約請求,每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間,因此她不能接受相鄰的預約。給定一個預約請求序列,替按摩師找到最優的預約集合(總預約時間最長),返回總的分鍾數。
遞歸方法 :


public static int rec_opt(int []arr,int i){
    //遞歸終止的條件,意味着如果只能選第一個,那么最好的方法就是arr[0]
    if(i==0)
        return arr[0];
    //處理特殊情況,因為題目要求間隔選擇
    else if(i==1)
        return Math.max(arr[0],arr[1]);
    else{
        int a = rec_opt(arr,i-2) + arr[i];  //對於每一個顧客無非兩種情況,選或者不選,如果選的話,就是,i-2個的最優解加上當前的value
        int b = rec_opt(arr,i-1);           //如果不選,那么就只能使用上一個的最優解
        return Math.max(a,b);                 //最后比較兩種情況,得出當前情況的最優解
    }
}

非遞歸方法 :

public static int dp_opt(int []arr){
        int len =arr.length;
        if(len == 0) return 0;
        if(len == 1) return arr[0];
        int []opt = new int[len];
        opt[0]=arr[0];
        opt[1]=Math.max(arr[1],arr[0]);
        for(int i=2;i<len;i++){
            int a = opt[i-2] + arr[i];  //對於每一個顧客無非兩種情況,選或者不選,如果選的話,就是,i-2個的最優解加上當前的value
            int b = opt[i-1];           //如果不選,那么就只能使用上一個的最優解
            opt[i] = Math.max(a,b);     //最后比較兩種情況,得出當前情況的最優解
        }
        return opt[len-1];
    }
第二個例子:

給定一個數組和一個數字,如果數組中存在一個或多個數字相加可以得到該數字,則返回true,得不到則返回false(ps:暫時不考慮數組中有負數,和給的數字是負數的情況)
遞歸方法:

public static boolean rec_subset(int []nums,int i,int s){  //傳進來的是len-1表示,從后往前找可能的情況
   if(s==0) return true;   //如果s等於0表示已經找到了需要的數字
   else if(i==0) return nums[0]==s;    //如果找到了最后一個數字,也就是數組中的第一個數字,那么如果這個數與s不等,也就說明,該種情況不可能
   else if(nums[i]>s) return rec_subset(nums,i-1,s);   //如果當前數字大於s也就沒必要找這個分支,直接進入不用該數字的分支
   else{
       boolean a = rec_subset(nums,i-1,s-nums[i]); //對於每一個數字無非有兩種情況,選他和不選他,選他,就遞歸調用,求之前的數組中有無數字相加得到s-nums[i]
       boolean b = rec_subset(nums,i-1,s);            //不選:求之前的數組,有無數字相加得到s
       return a||b;
   }
}

非遞歸方法 :

public static boolean dp_subset(int []nums,int S){
    if(S<=0) return false;    //暫且不考慮小於等於零的情況
    int len = nums.length;
    boolean [][]subset = new boolean[len][S+1];     //新建二維數組保存子問題結果
    for(int i=0;i<S+1;i++) subset[0][i]=false;      //初始化第一行
    for(int i=0;i<len;i++) subset[i][0]=true;   //初始化第一列
    subset[0][nums[0]] = true;
    for(int i=1;i<len;i++)
        for(int s=1;s<S+1;s++)
            if(nums[i]>s)       //如果當前數字大於s也就沒必要找這個分支,直接進入不用該數字的分支
                subset[i][s] = subset[i-1][s];
            else
                subset[i][s] = subset[i-1][s-nums[i]] || subset[i-1][s];    //兩種情況的判斷
    return subset[len-1][S];
}

另外推薦學習b站正月點燈籠的動態規划教學視頻.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM