数据结构和算法(持续更新.....)

目录

二叉树的前序、中序、后续、遍历

递归算法

非递归的方法

二叉树的层次遍历

二叉树的路径和

二叉树的所有路径

排列

全排列  - 递归方法

上一个排列与下一个排列

下一个排列

第K个排列

字符串置换

分治法

判断是否是平衡树

二叉树的最大路径

是否查找二叉树

合并K个排序的链表

回溯法

子集

单词搜索

分割回文串

动态规划

经典问题就是0,1背包问题

N皇后问题

N皇后问题二


二叉树的前序、中序、后续、遍历

二叉树的结构

                                  

第一次到达该节点,就放入节点值到结果中,是前序遍历,

第二次到达该节点,就放入节点值到结果中,是中序遍历,

第三次到达该节点,就放入节点值到结果中,是后序遍历,

将链表转化为二叉树

public class TreeNode {
    TreeNode left,right;
    int val;

    public TreeNode(int val) {
        this.left = this.right = null;
        this.val = val;
    }

    public TreeNode(TreeNode treeNode){
        this.left = treeNode.left;
        this.right = treeNode.right;
        this.val = treeNode.val;
    }

    public static void main(String args[]){
        List<String> list = new ArrayList<String>(  );
        list.add( "2" );
        list.add( "1" );
        list.add( "4" );
        list.add( "#" );
        list.add( "#" );
        list.add( "3" );
        list.add( "5" );
        TreeNode root = treeConstruct( list );
        int i=0;
    }

    /**
     * 由链表构建二叉树
     * @param list
     * @return
     */
    public static TreeNode treeConstruct(List<String> list){

        TreeNode root = new TreeNode( Integer.valueOf( list.get( 0 ) ) );//先构造根节点
        TreeNode p = root;
        TreeNode curLeft,curRight;
        Queue<TreeNode> queue = new LinkedList<TreeNode>( );
        queue.add( p );

        TreeNode temp = queue.peek();
        int pos = 0;
        while(pos+1 <list.size()-1) {
            int size = queue.size();
            int pp = pos;
            for (int i = pos; i < pp+size*2; i += 2) {//在数组中取数,每次增加2,因为有左右俩节点
                p = queue.poll();//remove  and return head
                if ( pos + 1 < list.size()&&!list.get( pos + 1 ).equals( "#" ) ) {
                    curLeft = new TreeNode( Integer.valueOf( list.get( pos + 1 ) ) );
                    p.left = curLeft ;
                    queue.add( p.left );
                }
                if (  pos + 2 < list.size()&&!list.get( pos + 2 ).equals( "#" )) {
                    curRight = new TreeNode( Integer.valueOf( list.get( pos + 2 ) ) );
                    p.right = curRight ;
                    queue.add( p.right );
                }
                pos+=2;
            }
        }
        return temp;
    }
}
public class TreeNode {
     public int val;
     public TreeNode left, right;
     public TreeNode(int val) {
       this.val = val;
       this.left = this.right = null;
    }
}

递归算法

 {
  ArrayList<Integer> ret=new ArrayList<Integer>();
  TreeNode p=root;
  PreOrderTree(ret,p);
  return ret;
}
void PreOrderTree(ArrayList<Integer> ret,TreeNode p){
    if(p==null)
        return ;
    ret.add(p.val);//这一步的位置,确定了是前序、中序、后续
    PreOrderTree(ret,p.left);
    PreOrderTree(ret,p.right);
    }
}

非递归的方法

主要使用栈(stack)返回到上一节点。‘

前序遍历的非递归方法

    List<Integer>  ret=new ArrayList<Integer>();
    Stack<TreeNode> sta=new Stack<TreeNode>();
    if(root==null)
    return ret;
    TreeNode p=root;
    while(p!=null || !sta.empty()){
      ret.add(p.val);
      sta.push(p);
      p=p.left;
      //左节点为空,找到已存栈中第一个有右节点,再由该右节点再次循环从左开始查
      while(p==null && !sta.empty()){
          p=sta.pop().right;
      }
    }
    return ret;

中序遍历的非递归

    public List<Integer> inorderTraversal(TreeNode root) {
        // write your code here
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode p = root;
        List<Integer> ret = new ArrayList<Integer>();
        if(root == null){
            return ret;
        }
        while(p!=null || !stack.empty()){
            stack.push(p);
            p=p.left;
            while(p==null && !stack.empty()){
//因为中序遍历是第二次经过节点,所以从由节点取出的时候记录值
                p = stack.pop();
                ret.add(p.val);
                p=p.right;
            }
        }
        return ret;
    }

后序遍历的非递归

添加右节点被访问过的标记

    public List<Integer> postorderTraversal(TreeNode root) {
        // write your code here
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode flag=null ;
        List<Integer> ret = new ArrayList<Integer>();
        TreeNode p = root;
        if(root ==null){
            return ret;
        }
        while(p!=null){//放入所有的左节点
            stack.push(p);
            p=p.left;
        }
        while(!stack.empty()){
           p=stack.pop();
           if(p.right==null||p.right==flag){//右节点已经被访问过或为空
               ret.add(p.val);
               flag = p;
           }else{
               stack.push(p);
               p=p.right;
               while(p!=null){
                   stack.push(p);
                   p=p.left;
               }
           }
        }
        return ret;
    }

二叉树的层次遍历

    public List<List<Integer>> levelOrder(TreeNode root) {
        // write your code here
        List<List<Integer>> ret = new ArrayList<List<Integer>>();
      
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        if(root == null){
            return ret ;
        }
        TreeNode p = root;
        queue.add(root);
        while(!queue.isEmpty()){
            List<Integer> temp = new ArrayList <Integer>();
            int size = queue.size();
            for(int i=0;i<size;i++){//这里不能写成i<queue.size();大小是变化的
                p=queue.poll();
                temp.add(p.val);
                if(p.left!=null){
                    queue.add(p.left);
                }
                 if(p.right!=null){
                    queue.add(p.right);
                }
            }
            ret.add(temp);
        }
        return ret;
    }

二叉树的路径和

这个地方注意java中new 的对象,在使用的时候是使用地址引用的(传址),所以需要创建副本,不然存的对象都会是一个。

 public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) {
        // write your code here
        List<List<Integer>> listAll = new ArrayList<List<Integer>>();
        List<Integer> list = new ArrayList<Integer>();
        TreeNode p = root;
        if(root == null ){
            return listAll;
        }
        findPath(listAll,list,p,target);
        return listAll;
     
    }
    
    void  findPath(List<List<Integer>> listAll,List<Integer> list, TreeNode p , int target){
        list.add(p.val);
        if(p.left == null && p.right == null){
            if(isRightPath(list,target)){
                listAll.add(new ArrayList(list));
//这个地方要注意,如果不是新建的话结果会发现结果集相同
                return ;
            }
        }
        if(p.left != null){
            findPath(listAll,list,p.left,target);
             list.remove(list.size()-1);
        }
        
         if(p.right != null){
             findPath(listAll,list,p.right,target);
              list.remove(list.size()-1);
        }
    }
    
    public boolean isRightPath(final List<Integer> list,final int target){
        int sum = 0;
        for(int x : list ){
            sum+=x;
        }
        return sum == target;
    }

二叉树的所有路径

    public List<String> binaryTreePaths(TreeNode root) {
        // write your code here
        List<String> list = new ArrayList<String>();
        if(root == null){
            return list;
        }
        TreeNode p = root;
        String temp = new String();
        getAllPath(p,temp,list);
        return list;
    }
    
    void getAllPath(TreeNode p,String temp, List<String> list){
        if(temp.equals("")){//java中new的对象在堆内存中,用equals比较方法
            temp += p.val;
        }else{
            temp += "->" + p.val;
        }
        
        if(p.left == null && p.right == null){
            list.add(new String(temp));
            return ;
        }
        if(p.left != null){
            getAllPath(p.left,temp,list);
        }
        if(p.right != null){
             getAllPath(p.right,temp,list);
        }
    }

排列

全排列  - 递归方法

比如数组为[1,2,3,4]

当第一位为1时,求2,3,4的所有可能

当第一位为2时,求1,3,4的所有可能

当第一位为3时,求1,2,3的所有可能

可以按照找规律方法,当第一位确定的时候,其实就是找剩下位置的全排列,可以通过递归的方法来递归求解,当第一位确定了之后,再通过递归的方法来确定剩下的位数的全排列结果。

 public List<List<Integer>> permute(int[] nums) {
        // write your code here
        List<List<Integer>> ret = new ArrayList<List<Integer>>();
        List<Integer> temp = new ArrayList<Integer>();
        if(nums.length == 0){
            ret.add(temp);
            return ret ;
        }
        if(nums.length == 1){
            temp.add(nums[0]);
            ret.add(temp);
            return ret ;
        }
        getAllSort(0,temp,ret,nums);;
        return ret;
    }
    
    void getAllSort(int pos,List<Integer> temp,List<List<Integer>> ret,int[] nums){
        if(temp.size()==nums.length){
            ret.add(new ArrayList(temp));
            return ;
        }
        
        for(int i= pos; i<nums.length;i++){
            
            int tep = nums[i];//swap操作,第pos位6的可能
            nums[i] = nums[pos];
            nums[pos] = tep ;
            
            temp.add(nums[pos]);
            
            getAllSort(pos+1,new ArrayList(temp),ret,nums);
            
            temp.remove(temp.size()-1);
            
            int tep2 = nums[i];//换回来,返回到初始的状态
            nums[i] = nums[pos];
            nums[pos] = tep2 ;
        }
    }

上一个排列与下一个排列

笨点的方法就是先把给出的结果全排列出来,再再结果列表中查找上一个或者下一个排列的可能

上一个排列:从后往前查找第一个递增,即list.get(i)>list.get(i+1),再在 i  后查找到最大但同时小于list.get(i) 的元素(位于j处),将i,j元素相互交换,再将I位置以后的进行反转操作,就可以得到上一个队列

 public List<Integer> previousPermuation(List<Integer> nums) {
        // write your code here
        if(nums.size()==0||nums.size()==1)
            return nums;
        List<Integer> ret = new ArrayList<Integer>();
        int len = nums.size()-2;
         for(;len>=0;len--){
            if(nums.get(len)>nums.get( len+1)){
                break;
            }
        }
       return aboveSort(len,nums);
    }
    
    public List<Integer> aboveSort(int len ,List<Integer> list){
        
        if(len<0){
            //全部反转
             Collections.reverse(list);
             return list;
        }else{
        //部分反转,先交换两个数的位置,再将len后的数组反转
                   int  pos = list.size()-1;
         int  max = Integer.MIN_VALUE;
         int maxValuePos =  list.size()-1;
         for( ;pos>len;pos--){
             if(list.get( pos )>max&&list.get(pos)<list.get(len)){
                 max = list.get( pos );
                 maxValuePos = pos;
             }
         }
        Collections.swap( list,len,maxValuePos );
        len++;
        int size = list.size()-1;
        int i=0;
        while(len + i < size - i ){
            Collections.swap(list,len+i,size -i );
            i++;
        }
        return list;
        }
      
    }

下一个排列

与上一个排列相似,从后往前找第一个满足list.get(i)<list.get(i+1),再从后往前找到第一个比list.get(i)大的数(j),交换i,j,再将i之后的元素进行反转

    public int[] nextPermutation(int[] nums) {
        // write your code here
        if(nums.length<=1){
            return nums;
        }
        int size = nums.length - 1 ;
        int pos = size-1;
        for(;pos>=0;pos--){
            if(nums[pos]<nums[pos+1]){
                break ;
            }
        }
        if(pos<0){
            //全部反转
            int begin = 0;
            int count = 0;
            while(begin+count<size-count){
                int temp = nums[begin+count];
                nums[begin+count] = nums[size-count];
                nums[size-count] = temp;
                count++;
            }
            return nums;
        }else{
            // find first bigger val
            int firGre = size;
            for(int i =size;i>=pos;i--){
                if(nums[i]>nums[pos]){
                    firGre = i;
                    break;
                }
            }
            //swap
            int temp = nums[pos];
            nums[pos] = nums[firGre];
            nums[firGre] = temp;
            //reverse
            pos++;
            int count = 0;
            while(pos+count<size-count){
                temp = nums[pos+count];
                nums[pos+count] = nums[size-count];
                nums[size-count] = temp;
                count++;
            }
            return nums;
        }
    }

第K个排列

本来是想全排列或则进行n-1次的下一次下一个队列的操作,后来看网上的大佬们的神奇操作,找到了数学的规律。。

每一位上的数字为  num = k/(n-1)!  ;

然后在list中数字删掉,数字不重复。

之后K减去(num-1)*(n-1)!  ,   n也要减一:n-1

引用博客的地址:https://blog.csdn.net/qq_38310176/article/details/81227086

    public String getPermutation(int n, int k) {
        // write your code here
        
        String result = "";
		List<Integer> v = new ArrayList<Integer>();
		for(int i=1;i<=n;i++) v.add(i);
		int num = 0, f = 0;
		for(int i=1;i<n;i++) {
			k -= (num-1)*f;
			f = Solution.Factorial(n-i);
			num = (int)Math.ceil((double)k/f);
			result += String.valueOf(v.get(num-1));
			v.remove(num-1);
		}
		return result+v.get(0);
	}
    public static int Factorial(int n) {
		while(n > 1) {
			return n*Factorial(n-1);
		}
		return 1;
	}

字符串置换

判断一个字符串是否可以通过位移来变换成另一个字符串

通过ASCLL码比较最后相加结果是否相同,或者按照字典排序,在比较两个字符串是否相等

  public boolean Permutation(String A, String B) {
        // write your code here
        if(A == null && B == null){
            return true;
        }
        char[] a = A.toCharArray();
        char[] b = B.toCharArray();
        if(a.length != b.length){
            return false;
        }
        int aASC = 0;
        int bASC = 0;
        for(int  i=0;i<a.length;i++){
            aASC+=a[i];
            bASC+=b[i];
        }
        if(aASC == bASC){
            return true;
        }
        return false;
    }

分治法

判断是否是平衡树

分别从左右两分支判断左右子树是否为平衡树,再比较左右两子树是否都为平衡树,思想类似二分法,分开查询,最后再判断结果并集

 public boolean isBalanced(TreeNode root) {
        // write your code here
        if(root == null){
            return true;
        }
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);
        if(Math.abs(leftDepth-rightDepth)>1){
            return false;
        }else{
           return isBalanced(root.left)&&isBalanced(root.right);
        }
    }
    
    //查找当前节点的最大深度
    int maxDepth(TreeNode root){
        if(root == null){
            return 0;
        }
        int left = maxDepth(root.left)+1;
        int right = maxDepth(root.right)+1;
        return  left > right ? left : right;
    }

二叉树的最大路径

这个问题用C++很简单,就是分治,左右两子树查找最大的路径,选出左右路径最大的那条,返回代表这节点最大的路径,最后比较左右节点最大路径相加和已有的路径相比。使用java就需要注意传值和传址的问题,基础数据类型都是传值(不含String),我这里使用是数组的方法解决

 public int maxPathSum(TreeNode root) {
        // write your code here
        
        int[] sum =new int[1];
        sum[0] = Integer.MIN_VALUE;
        maxSum(root,sum);
        return sum[0] ;
    }
    
    int maxSum(TreeNode root,int[] sum){
        if(root == null){
            return 0;
        }
        //左右子树的最大路径,0是可能不选这条子路径上的节点或者真的路径和就是0
        int left = maxSum(root.left,sum);
        int right = maxSum(root.right,sum);
        sum[0] = Math.max(sum[0],Math.max(0,left)+Math.max(0,right)+root.val);
        return Math.max(0,Math.max(left,right))+root.val;
    }

是否查找二叉树

从左叉是递减的,右叉是递增的,且左子树节点都小于该节点,右子树都大于该节点。所以判断左子树和右子树不仅要判断是递减或递增,还要判断,左子树的所有节点都小于该父节点,右子树的所有节点都大于该父节点。

    boolean firstNode=true; //判断左子树还是右子树
    int lastVal = Integer.MAX_VALUE; //存放当前子树的父节点的值
    public boolean isValidBST(TreeNode root) {
        // write your code here
        if(root == null){  
            return true;  
        }  
        if(!isValidBST(root.left)){  
            return false;  
        }  
        if(!firstNode && lastVal >= root.val){  //右子树值小于当前子树父节点的值
            return false;  
        }  
        firstNode = false;  
        lastVal = root.val;  
        if(!isValidBST(root.right)){  
            return false;  
        }  
        return true;  
    }

合并K个排序的链表

多个两个链表合并的操作

public ListNode mergeKLists(List<ListNode> lists) {  
        // write your code here
        if(lists.size()==0){
            return null;
        }
        if(lists.size()==1){
            return lists.get(0);
        }
        int size = lists.size();
        while(size > 1){
            int k = (size+1)/2;
             for (int i = 0; i < size / 2; ++i) {
                lists.set(i,mergr(lists.get(i), lists.get(i+k)));
            }
            size = k;
        }
        return lists.get(0);
        }
    
    ListNode mergr(ListNode l1,ListNode l2){
        ListNode head = new ListNode(-1);
        ListNode p = head;
        while(l1!=null&&l2!=null){
            if(l1.val<l2.val){
               head.next = new ListNode(l1.val);
               l1=l1.next;
            }else{
               head.next = new ListNode(l2.val);
               l2=l2.next;
            }
             head = head.next;
        }
        while(l1 != null){
             head.next = new ListNode(l1.val);
               l1=l1.next;
            head = head.next;
        }
         while(l2 != null){
             head.next = new ListNode(l2.val);
               l2=l2.next;
                head = head.next;
        }
        return p.next;
        
    }

回溯法

回溯法主要是返回上一步的状态,类似的全排列,子集等

子集

给出一个数组,由前一步返回到这一步时,将状态回滚

例如给出给出数组[1,2,3]

初始时Pos为0

temp   []      [1]  [1,2]  [1,2,3] ,[1,3]

当pos 0执行完,temp此时清空 []

当pos =1

temp  [2] ,[2,3] 

当pos =2

temp [3]

此时得到所有的结果子集

 public List<List<Integer>> subsets(int[] nums) {
        // write your code here
        List<List<Integer>> ret = new ArrayList<List<Integer>>();
        List<Integer> temp = new ArrayList<Integer>();
        
        if(nums.length == 0){
            ret.add(temp);
            return ret ;
        }
        
        Arrays.sort(nums);
        getAllSonSort(0,nums,ret,temp);
        return ret ;
    }
    
    void getAllSonSort(int pos, int[] nums, List<List<Integer>> ret, List<Integer> temp){
        ret.add(new ArrayList(temp));
        
        for(int i=pos;i<nums.length;i++){
            temp.add(nums[i]);
            getAllSonSort(i+1,nums,ret,temp);
            temp.remove(temp.size()-1);
        }
    }

单词搜索

给出board =

["ABCE", "SFCS", "ADEE"]

word = "ABCCED", ->返回 true,word = "SEE",-> 返回 true,word = "ABCB", -> 返回 false.

一开始想到的方法就是暴力破解,从每个节点开始查,上下左右再去遍历得到结果,代码比较臃肿。

public class WordSearch {

    public static void main(String args[]){
        char[][] board = new char[][]{{'A','B','C','E'},
                          {'S','F','C','S'},
                          {'A','D','E','E'}};

        String word = new String( "ABCCEE" );
        if(exist( board,word )){
            System.out.println( "true" );
        }else{
            System.out.println( "false" );
        }

    }

    public static boolean exist(char[][] board,String word){
        int height = board.length;
        int weight = board[0].length;
        String temp = new String();

        if(word.length()==0){
            return true;
        }

        for(int i=0;i<height;i++) {
            for (int j = 0; j < weight; j++) {
                temp = "";
                //每次查询时,初始化访问路径
                Boolean[][] visit = new Boolean[height][weight];//存放该节点是否访问过
                for(int k=0;k<height;k++){
                    for(int l=0;l<weight;l++){
                        visit[k][l] = false;
                    }
                }
                //查询该节点为起点是否满足
                if(mathWord(i,j,visit,board,word)){
                    return true;
                }
            }
        }
        return false;
    }

    //由某点开始是否可以得到这个单词
    public static boolean mathWord(int cur,int row,Boolean[][] visit,char[][] board,String word){
        if(word.length() == 0){
            return true;
        }
        //越界条件
        if(cur<0 || cur>=board.length || row<0 || row >= board[0].length) {
            return false;
        }
        String ch = word.substring( 0,1 );
        String bo = String.valueOf( board[cur][row] );
        if((ch.equals( bo )) && (visit[cur][row] == false)){
            visit[cur][row] = true;
            String temp = new String( word.substring( 1 ) );
            boolean res = mathWord( cur+1,row,visit,board,temp)||mathWord( cur-1,row,visit,board,temp)||
                    mathWord( cur,row+1,visit,board,temp)||mathWord( cur,row-1,visit,board,temp);
            visit[cur][row] = false;
            return res;
        }
        return false;
    }

}

分割回文串

不改变字符串的顺序,将元素分割成为可以回文的字符数组

public class BackString {
    public static void main(String args[]){

        String str = new String("aabb");
        backString(str );
        int i=0;
    }

    public static List<List<String>> backString(String str){
        List<List<String>> ret = new ArrayList<List<String>>( );
        List<String> list =new ArrayList<String>( );
        if(str.length()<=1){
            list.add( str );
            ret.add( list );
            return ret;
        }
        getAllBackStr(0,str,list,ret);
        return ret ;
    }

    public static void getAllBackStr(int pos,String str,List<String> list,List<List<String>> ret){
        if(pos >= str.length()){
            ret.add( new ArrayList<String>( list ) );
            return ;
        }
        for(int i=pos;i<str.length();i++){
            String temp = new String( str.substring( pos,i+1 ) );//获取相应的字符串
            if(!isBackStr( temp )){
                continue;
            }
            list.add( temp );
            getAllBackStr(i+1,str,list,ret);
            list.remove( list.size()-1 );
        }
    }



    public static boolean isBackStr(String stri){
        int len = stri.length();
        if(stri==null || stri.equals( "" )){
            return false;
        }
        if(len <= 1 ){
            return true;
        }
        for(int i=0;i<=len/2-1;i++){
            char a = stri.charAt( i );
            char b = stri.charAt( len-i-1 );
            if(a != b){
                return false;
            }
        }
        return true;
    }
}

动态规划

经典问题就是0,1背包问题

动态规划的主要找出上一步和下一步的关系。

经典的背包问题为: 如果有4个物品[2, 3, 5, 7]

如果背包的大小为11,可以选择[2, 3, 5]装入背包,最多可以装满10的空间。

如果背包的大小为12,可以选择[2, 3, 7]装入背包,最多可以装满12的空间。

函数需要返回最多能装满的空间大小。

假设创建二维数组 dp[a.size] [m] 用来处理上一部与下一步的关系

初始化dp[0][ ] 为0

dp[i] [j]为能否放入第I个物体,其中j为此时的容量大小

当j>a[i]

满足关系 dp[i][j] = Math.max(dp[i-1][j] , dp[i-1][j-a[i]] +a[i]);

不然就直接继承上一种

dp[i][j] = dp[i-1][j]

这种方法比较容易理解,但是在lintcode中会报limit memory.使用的空间还是太多了。

public class PackageProblem {
    public static void main(String args[]){
        int[] a = {2,3,5,7};
        int count = 12;
        int num = getMaxWight(a,count);
        int i=0;
    }

    public static int getMaxWight(int[] a,int count){
        int len = a.length;
        int[][] dp = new int[len][count+1];

        //初始化动态规划的结果集
        for(int i=0;i<len;i++){
            for(int j=0;j<count+1;j++){
                dp[i][j] = 0;
            }
        }
        //第一个物体放入的可能结果集
        for(int i=0;i<=count;i++){
            if(i>=a[0]){
                dp[0][i] = a[0];
            }
        }

        for(int i=1;i<len;i++){
            for(int j =1;j<=count;j++){
                if(j>a[i]){//当前的内存能够放入第i个物体
                    dp[i][j] = Math.max( dp[i-1][j],dp[i-1][j-a[i]]+a[i] );//比较放入第i个物体和不放入第i个物体的最大值
                }else{
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return  dp[len-1][count];
    }

}

 

N皇后问题

皇后之间不能再同一条线上,及不能在45‘,135,斜线上有皇后存在。

判断条件可以为

创建List<Integer> 存放每行皇后的位置。

temp.get(i) == c || Math.abs(row-i) == Math.abs( c-temp.get(i))
public class NumQueenProblem {
    public static void main(String args[]){
        int n = 4;
        solveNQueens( n );
    }

    public static List<List<String>> solveNQueens(int n){
        List<List<String>> solutions = new ArrayList<List<String>>( );
        List<Integer> temp = new ArrayList<Integer>( );//记录当前行的位置信息
        for(int i=0;i<n;i++){
            temp.add( -1 );
        }
        getAllSolution(solutions,temp,n,0);
        return solutions;
    }
    public static void getAllSolution(List<List<String>> solutions,List<Integer> temp,int n,int row){
        if(row >= n){
            List<String> solution = new ArrayList<String>( getResult( temp ) );
            solutions.add( solution );
        }else {
            for (int i = 0; i < n; i++) {
                if(isValid( temp,row,i )){
                    temp.set( row,i );
                    getAllSolution(solutions,temp,n,row+1);
                }

            }
        }
    }
    //判断该点是否满足N皇后规则,不在一条线上且不相邻
    public static boolean isValid(List<Integer> temp , int row, int c){
        if( temp.size() == 0 ){
            return true;
        }
        for(int i=0;i<row;i++){
            if(temp.get(i) == c || Math.abs(row-i) == Math.abs( c-temp.get(i) )){
                return  false ;
            }
        }
        return true;
    }

    //将链表转换为字符串链表
    public static List<String> getResult(List<Integer> temp){
        if(temp.size() == 0) {
            return new ArrayList<String>();
        }
        List<String > ret = new ArrayList<String>(  );
        int len = temp.size();
        for(int i=0;i<len;i++){
            String tep = new String();
            //第i行的字符串
            for(int k=0;k<len;k++){
                if(k == temp.get( i )){
                    tep+="Q";
                }else{
                    tep+=".";
                }
            }
            ret.add( tep );
        }
        return ret;
    }
}

N皇后问题二

还是要注意java中传值和传址的问题,我怎么还在猥琐用数组呢???,要抽时间写一篇关于传值和传址的博客了

public class Solution {
    /**
     * @param n: The number of queens.
     * @return: The total number of distinct solutions.
     */
    public int totalNQueens(int n) {
        // write your code here
         int[] solutions = new int[1];
         solutions[0]=0;
        List<Integer> temp = new ArrayList<Integer>( );//记录当前行的位置信息
        for(int i=0;i<n;i++){
            temp.add( -1 );
        }
        getAllSolution(solutions,temp,n,0);
        return solutions[0];
    }
    
     public  void getAllSolution(int[] solutions,List<Integer> temp,int n,int row){
        if(row >= n){
           solutions[0]++;
        }else {
            for (int i = 0; i < n; i++) {
                if(isValid( temp,row,i )){
                    temp.set( row,i );
                    getAllSolution(solutions,temp,n,row+1);
                }

            }
        }
    }
    public  boolean isValid(List<Integer> temp , int row, int c){
        if( temp.size() == 0 ){
            return true;
        }
        for(int i=0;i<row;i++){
            if(temp.get(i) == c || Math.abs(row-i) == Math.abs( c-temp.get(i) )){
                return  false ;
            }
        }
        return true;
    }
}

排序算法

快速排序(第K大元素)

public class Solution {
    /**
     * @param n: An integer
     * @param nums: An array
     * @return: the Kth largest element
     */
    public int kthLargestElement(int n, int[] nums) {
        // write your code here
         if(n > nums.length){
			return 0;
		}
		int start=0;
		int end=nums.length-1;
		int index=partition(nums, 0, nums.length-1);
		while(index != nums.length-n){
			 if(index > nums.length-n){
				 index=partition(nums, start, index-1);
			 }else{
				 index=partition(nums, index+1, end);
			 }
		}
		return nums[index];
    }
     private  int partition(int []nums,int start,int end){
		int left=start;
		int right=end;
		int pivot=nums[start];
		while(left<right){
			while(left<right&&nums[right]>=pivot)
				right--;
			if(left<right){
				nums[left]=nums[right];
				left++;
			}
			while(left<right&&nums[left]<pivot)
				left++;
            if(left<right){
            	nums[right]=nums[left];
            	right--;
            }
		}
		nums[left]=pivot;
		return left;
	}
  
}

猜你喜欢

转载自blog.csdn.net/qq_38733069/article/details/86084907
今日推荐