leetcode演算法題解(Java版)-9-N皇后問題

kissjz發表於2018-05-05

一、貪心

題目描述

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array[−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray[4,−1,2,1]has the largest sum =6.

click to show more practice.
More practice:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

思路

  • 貪心的基本思想就是區域性找最優解,然後通過區域性的最優解得出來的結果,就是全域性的最優解,往往很難證明,但不妨先試一試。
  • 就像這道題,因為要求的是最大的子串和,那顯然負數是起到反作用的,所以如果當前和是負的,那就果斷捨去,這也是貪心的思路。
  • 這樣的解法時間複雜度是O(n)題目中說明了,可以使用分治進一步優化,請看程式碼二。

程式碼一

public class Solution {
    public int maxSubArray(int[] A) {
        int len=A.length;
        if(len==0){
            return 0;
        }
        int sum=A[0];
        int max=A[0];
        for(int i=1;i<len;i++){
            if(sum<0){
                sum=0;
            }
            sum+=A[i];
            if(sum>max){
                max=sum;
            }
        }
        return max;
    }
}

程式碼二

public class Solution {
        public int div(int [] A,int left,int right){
            int mid=(left+right)/2;
            if(left==right){
                return A[left];
            }
            int max1=div(A,left,mid);
            int max2=div(A,mid+1,right);
            int max3=-999999;//這裡不嚴謹,但不能用Integer.MIN_VALUE。
            //否則max3+max4如果是負數和Integer.MIN_VALUE相加會溢位
            int max4=-999999;
            int tem=0;
            for(int i=mid;i>=left;i--){
                tem+=A[i];
                max3=Math.max(max3,tem);
            }
            tem=0;
            for(int i=mid+1;i<=right;i++){
                tem+=A[i];
                max4=Math.max(max4,tem);
            }
            return Math.max(Math.max(max1,max2),max3+max4);        
        }
    public int maxSubArray(int[] A) {
        int len=A.length;
        if(len==0){
            return 0;
        }
        return div(A,0,len-1);
    }
    
}

二、N皇后問題

題目描述

Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.

思路

  • 經典的老題目了,儲存當然是用一個陣列map解決:下標表示行號,每個map[i]中存放的數字表示列號。
  • 然後就是寫一個判斷函式:1.判斷行是否重複:這個不需要判定,因為陣列下標即使行。2.判斷列是否重複,即map[t]!=map[i]。3.判斷對角線是否重複:即map[t]-map[i]!=t-i。

程式碼

public class Solution {
    public int [] map=new int[30];
    public int count=0;//注意!!不能寫成public static int count=0;
    //否則全域性靜態變數的話,記憶體地址是一個,
    //也就是當前測試用例會受到上一個測試用例中count的影響
    public int totalNQueens(int n) {
        backtrack(1,n);
        return count;
    }
    public void backtrack(int t,int n){
        if(t>n){
            count++;
        }
        else{
            for(int i=1;i<=n;i++){
                map[t]=i;
                if(valid(t)){
                    backtrack(t+1,n);
                }
            }
        }
    }
    public boolean valid(int t){
        for(int i=1;i<t;i++){
            if(Math.abs(t-i)==Math.abs(map[t]-map[i])||map[i]==map[t]){
                return false;
            }
        }
        return true;
    }
}

三、N皇后問題再度升級

題目描述

The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens` placement, where`Q`and`.`both indicate a queen and an empty space respectively.
For example,
There exist two distinct solutions to the 4-queens puzzle:

[
 [".Q..",  // Solution 1
  "...Q",
  "Q...",
  "..Q."],

 ["..Q.",  // Solution 2
  "Q...",
  "...Q",
  ".Q.."]
]

思路

  • 和上一道只需要輸出個數,這道題也需要把所有的圖輸出來。只需要改動一個地方就OK。具體的看程式碼,寫的很清楚。

程式碼

import java.util.ArrayList;

public class Solution {
    public int [] mark=new int [30];
    public int count=0;
    public ArrayList<String[]> resList=new ArrayList<>();
    public ArrayList<String[]> solveNQueens(int n) {
        backtrack(1,n);
        return resList;
    }
    public StringBuilder drawOneLine(int n){
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<n;i++){
            sb.append(`.`);
        }
        return sb;
    }
    public boolean valid(int t){
        for(int i=1;i<t;i++){
            if(Math.abs(mark[i]-mark[t])==Math.abs(i-t)||mark[i]==mark[t]){
                return false;
            }
        }
        return true;
    }
    public void  backtrack(int t,int n){
        if(t>n){
            String [] tem=new String[n];
            for(int i=0;i<n;i++){
                StringBuilder line=drawOneLine(n);
                line.setCharAt(mark[i+1]-1,`Q`);//因為String從0開始而我的mark是從1開始記的
                //這裡下標有點亂:mark陣列是從1開始的,而tem是從0開始的。
                tem[i]=line.toString();
            }
            resList.add(tem);
        }
        else{
            for(int i=1;i<=n;i++){
                mark[t]=i;
                if(valid(t)){
                    backtrack(t+1,n);
                }
            }
        }
    }
    
}


相關文章