算法(3)

26.二叉搜索树与双向链表

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
 

中序遍历思路:
按照右中左的顺序,中序遍历对节点的访问顺序和转换完链表从左到右的顺序是一样的。所以在中序遍历时完成相邻两个节点的互指即可。

具体做法是把前一个节点记录下来然后pre->right=cur;cur->left=pre。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    TreeNode pre = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null) return pRootOfTree;
         
        Convert(pRootOfTree.right);
        if(pre == null){
            pre = pRootOfTree;
        } else {
            pre.left = pRootOfTree;
            pRootOfTree.right = pre;
            pre = pRootOfTree;
        }
        Convert(pRootOfTree.left);
         
        return pre;
    }
}
View Code

最开始我采用的是这种解法,有两个问题:

1.采用左中右的中序遍历,遍历完之后头结点还得从右到左挪回来

2.更严重的问题是,我将pre设置为局部传递的变量,由于pre是引用的值传递,在递归回退的时候,pre的引用时上一次遍历pre的副本,而不是遍历后更改的值。解决方法就是讲pre设置为全局变量。

切记!!!java只有值传递!只有值传递!只有值传递!

对于基本类型,java都是传值。而对于引用类型,其实java也是通过值传递的,只是传递的值不是实例本身,而是实例的引用的副本。

参考java的传值与传引用

错误解法:

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null)
            return null;
        TreeNode pre = null;
        ConvertHelper(pRootOfTree,pre);
        TreeNode res = pRootOfTree;
        while(res.left != null){
            res = res.left;
        }
        return res;
    }
    
    public void ConvertHelper(TreeNode cur, TreeNode pre){
        if(cur == null)
            return;
        ConvertHelper(cur.left,pre);
        cur.left = pre;
        if(pre!=null) pre.right = cur;
        pre = cur;
        ConvertHelper(cur.right,pre);
    }
}
View Code

非递归实现:

链接:https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5
来源:牛客网

import java.util.Stack;
public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null) return pRootOfTree;
         
        TreeNode list = null;
        Stack<TreeNode> s = new Stack<>();
        while(pRootOfTree != null || !s.isEmpty()){
            if(pRootOfTree != null) {
                s.push(pRootOfTree);
                pRootOfTree = pRootOfTree.right;
            } else {
                pRootOfTree = s.pop();
                if(list == null)
                    list = pRootOfTree;
                else {
                    list.left = pRootOfTree;
                    pRootOfTree.right = list;
                    list = pRootOfTree;
                }
                pRootOfTree = pRootOfTree.left;
            }
        }
         
        return list;
    }
}
View Code

27.字符串的排列

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
    public ArrayList<String> Permutation(String str) {
       ArrayList<String> list = new ArrayList<String>();
       if(str !=null && str.length() > 0){
           PermutationHelper(str.toCharArray(),0,list);
           Collections.sort(list);
       }
       return list; 
    }
    
    public void  PermutationHelper(char[] cs, int i, ArrayList<String> list){
        if(cs.length-1 == i){
            String val = String.valueOf(cs);
            if(!list.contains(val)){
                list.add(val);
            }
        }else{
            for(int j=i; j<cs.length;j++){
                swap(i,j,cs);
                PermutationHelper(cs,i+1,list);
                swap(i,j,cs);
            }
        }
    }
    
    public void swap(int i,int j,char[] cs){
        char temp = cs[i];
        cs[i] = cs[j];
        cs[j] = temp;
    }
}
View Code

 最后一个循环是递归调用swap交换前后两个字符,在最后交换完成入List之后再交换回来,回到初始状态再进下一个循环

28.数组中出现次数超过一半的数字

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
第一种普通解法:耗时10ms
import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        Map<Integer,Integer> count = new HashMap<>();
        if(array.length == 1)
            return array[0];
        for(int i:array){
            if(!count.containsKey(i)){
                count.put(i, 1);
            }else{
                count.put(i,count.get(i)+1);
                if(count.get(i) > array.length/2)
                    return i;
            }
        }
        return 0;
    }
}
View Code

第二种解法:耗时10ms

采用阵地攻守的思想:
第一个数字作为第一个士兵,守阵地;count = 1;
遇到相同元素,count++;
遇到不相同元素,即为敌人,同归于尽,count--;当遇到count为0的情况,又以新的i值作为守阵地的士兵,继续下去,到最后还留在阵地上的士兵,有可能是主元素。
再加一次循环,记录这个士兵的个数看是否大于数组一般即可。

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
       if(array.length == 1)
            return array[0];
       int result = array[0];
       int times = 0;
       for(int i = 0;i<array.length; i++){
           if(times == 0){
               result = array[i];
               times = 1;
           }else if(result == array[i]){
               times++;
           }else{
               times--;
           }
       }
        
        times=0;
        for(int i=0;i<array.length;i++){
            if(result==array[i]){
                times++;
            }
       }
       if(times*2<=array.length){
           result=0;
       }
       return result;
        
}
}
View Code

29.最小的K的个数

题目描述

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
偷懒解法(利用jdk自带的排序api):
import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> list = new ArrayList<>();
        if(k>input.length)
            return list;
        Arrays.sort(input);
        for(int i:Arrays.copyOfRange(input, 0, k)){
            list.add(i);
        }
        return list;
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/xiangkejin/p/9140134.html