剑指offer ---java版本


面试题 3二维数组的查找
    public static boolean find(int [][] a,int val){
        if(a==null) return false;
        int rows=a.length;
        int colums=a[0].length;
        int i=0,j=colums-1;
        while(i<rows&&j>=0){
            if(a[i][j]==val) return true;
            else if(a[i][j]>val) j--;
            else i++;
        }
        return false;
    }


面试题 4字符串中空格的替换,替换为20%,O(1)的空间复杂度
思路:先计算出替换后的总的长度,然后从后向前遍历,替换

    public static void blankReplace(char[] c){
        if(c==null) return;
        int cnt=0;
        for(int i=0;i<c.length;i++){
            if(c[i]==' ') cnt++;
        }
        int j=c.length+2*cnt;
        int i=c.length-1;
        while(i>=0){
            if(c[i]==' '){
                c[j--]='%';
                c[j--]='0';
                c[j--]='2';
            }
            else c[j--]=c[i];   
            i--;
        }
        return;
    }


面试题 5从尾到头打印单链表,可以使用栈,也可以用递归

    public static void tailTohead(ListNode head){
        if(head==null) return;
        Stack<Integer> save=new Stack<>();
        while(head!=null){
            save.push(head.val);
            head=head.next;
        }
        while(!save.isEmpty()){
            System.out.print(save.pop());
        }
    }


    public static void tailTohead(ListNode head){
        if(head==null) return;
        if(head.next!=null){
            tailTohead(head.next);
        }
        System.out.print(head.val);
    }



面试题 6重建二叉树,根据前序遍历和中序遍历递归构建左右子树,  
    public static class BinaryTreeNode {
            int value;
            BinaryTreeNode left;
            BinaryTreeNode right;
        }
    public static BinaryTreeNode rebuildTree(int [] prerder,int [] inOrder){
        if(prerder==null||inOrder==null||preOrder.length!=inOrder.length) return null;
        return (preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1);
    }

    public static BinaryTreeNode helper(int [] preOrder,int ps,int pe,int [] inOrder,int is,int ie){
        if(ps>pe) return null;
        int val=preOrder[ps];
        int index=is;
        while(index<=ie&&inOrder[index]!=val){
            index++;
        }
        BinaryTreeNode node=new BinaryTreeNode();
        node.val=val;
        node.left(preOrder,ps+1,ps+index-is,inOrder,is,index-1);
        node.right(preOrder,ps+index-is+1,pe,inOrder,index+1,ie);
        return node;
    }


面试题 7用两个栈实现队列  
核心思路:一个用来入队,一个辅助栈用来出队
public class stackToQueue{
    Stack s1=new Stack<>();
    Stack s2=new Stack<>();

    public static void inPut(int x){
        s1.push(x);
    }

    public static void outPut(int x){
        is(s1.size()+s2.size()!=0){
            if(!s2.isEmpty()){
                System.out.print(s2.pop());
            }
            else{
                helper();
                System.out.print(s2.pop());
            } 
        }
        else return;
    }
    public static void helper(){
        while(!s1.isEmpty()){
            s2.push(s1.poll());
        }
    }   
}

扩展 用2个队列实现一个栈
核心思想是 入栈时候就是入队到非空的队列,出栈就是把非空队列的n-1个元素转移到队列2中,然后弹出最后一个
public class queueToStack{

    Queue q1=new LinkedList<>();
    Queue q2=new LinkedList<>();

    public static void inStack(int x){      
        if(q1.size()==0){
            q2.offer(x);
        }
        else q1.offer(x);
    }
    public static void outStack(){
        if(q1.size()+q2.size()!=0){
            if(!q1.isEmpty(){
                helper(q1,q2);
                System.out.print(q1.poll());
            }
            else{
                helper(q2,q1);
                System.out.print(q2.poll());
            }   
        }   
    }
    public static void helper(Queue qu1,Queue qu2){
        if(!qu1.isEmpty()){
            while(qu1.size()>1){
                qu2.offer(qu1.poll());
            }
        }
    }   
}



面试题 8旋转数组的最小值,二分查找的变形,数组可以含有重复元素
核心思想是中点和右边界进行比较,同时维护一个最小值,

    public static int searchMin(int [] a){
        if(a==null) return -1;
        int i=0,j=a.length-1;
        int min=a[0];
        while(i<j-1){
            int mid=i+(j-i)/2;
            if(a[mid]>a[j]){
                min=Math.min(min,a[i]);
                i=mid+1;
            }
            else if(a[mid]<a[j]){
                min=Math.min(min,a[mid]);
                j=mid-1;
            }
            else{
                j--;
            }
        }
        min=Math.min(min,a[i]);
        min=Math.min(min,a[mid]);
        return min;
    } 

面试题 9求解裴波那契数列
递归和非递归版本

    public static int feibo(int n){
        if(n==0) return 0;
        if(n==1) return 1;
        return feibo(n-1)+feibo(n-2);
    }

    public static int feibo(int n){
        if(n==0) return 0;
        if(n==1) return 1;
        int preone=1,pretwo=0,curr=0;
        for(int i=2;i<=n;i++){
            curr=preone+pretwo;
            pretwo=preone;
            preone=curr;
        }
        return curr;
    }


面试题 10二进制中1的个数
核心思想是位操作,n&(n-1)相当于是把n最右侧的一个1变为0

    public static int countBits(int n){
        int cnt=0;
        while(n!=0){
            n=n&(n-1);
            cnt++;
        }
        return cnt;
    }

面试题 11数值的整数次方,doubleint次幂
主要的注意点是整数的正负和零,以及非法输入

    public static double powerExp(double base,int n){
        if(equal(base)&&n<0) {
            System.out.print("error");
            return 0.0;
            if(n>0){
                return helper(base,n);
            }
            else return 1.0/helper(base,n);
        }
    }

    public static equal(double a,double b){
        double c=Math.abs(a-b);
        if(c<0.0001){
            return true;
        } 
        return false;
    }

    public static double helper(double base,int n){
        if(n==0) return 1.0;
        if(n==1) return base;
        double res=helper(base,n>>1);//递归计算
        res=res*res;
        if(n&1==1){
            res=res*base;
        }
        return res;
    }

面试题 12打印从1到最大的N位数
本质属于一个大数问题,用数组存储进行全排列,然后从第一个非零元素开始输出

    public static void printMaxN(int n){
        if(n<0) return;
        int [] res=new int[n];//承载着n的信息
        pailie(0,res);
    }

    public static void pailie(int index,int [] arr){
        if(index>=arr.length){
            prinNum(arr);
        }
        for(int i=0;i<=9;i++){
            arr[index]=i;
            pailie(index+1,arr);
        }
    }

    public static void prinNum(int [] a){
        int key=0;
        while(key<a.length&&a[key]==0){
            key++;
        }
        for(int i=key;i<a.length;i++ ){
            System.out.print(a[i]);
        }
        if(key<a.length){
            System.out.println();
        }   
    }


面试题 13删除链表的结点O(1)
只访问这个结点,重点在于val的替换和结点的移位

    public static void delNode(ListNode node){
        if(node==null) return;
        if(node.next==null) {
            node==null;
            return;
        }
        node.next=node.next.next;
        node.val=node.next.val; 
    }


面试题 14调整数组顺序,奇数位于偶数前面,可以改变相对位置
解题思路使用双指针,一头一尾扫,一个遇到奇数同时另一个是偶数的时候交换

    public static void reOrder(int [] a){
        if(a.length<2) return;
        int i=0,j=a.length-1;
        while(i<j){
            while((a[i]&1)==1&&i<j){
                i++;
            }
            while((a[j]&1)==0&&i<j){
                j--;
            }
            if(i<j){
                int tmp=a[i];
                a[i]=a[j];
                a[j]=tmp;
            }
        }
    }


面试题 15寻找链表中的倒数第K个数  
核心就是快慢指针,快的先走K步然后慢的开始走,当快的走到头的时候慢指针的下一个就是倒数第K   

    public static ListNode findKth(ListNode head,int k){
        if(head==null||k==0) return head;
        ListNode fast=head,slow=head;
        for(int i=0;i<n;i++){
            fast=fast.next;
        }
        while(fast!=null){
            fast=fast.next;
            slow=slow.next;
        }
        return slow;
    }


面试题 16反转链表

    public static ListNode reverseList(ListNode head){
        if(head==null||head.next==null) return head;
        ListNode pre=null,curr=head,
        while(curr!=null){
            ListNode nex=curr.next;
            curr.next=pre;
            pre=curr;
            curr=nex;
        }
        return pre;
    }


面试题 17合并2个有序的链表

    public static ListNode merge(ListNode head1,ListNode head2){
        if(head1==null) return head2;
        if(head2==null) return head1;
        return helper(head1,head2);
    }

    public static ListNode helper(ListNode head1,ListNode head2){
        ListNode dump=new ListNode(0);
        ListNode p=dump;
        while(head1!=null&&head2!=null){
            if(head1.val<head2.val){
                p.next=head1;
                head1=head1.next;
                p=p.next;
            }
            else{
                p.next=head2;
                head2=head2.next;
                p=p.next;
            }
        }
        while(head1!=null){
            p.next=head1;
            head1=head1.next;
            p=p.next;
        }
        while(head2!=null){
            p.next=head1;
            head2=head2.next;
            p=p.next;
        }
        return dump.next;
    }


面试题 18树的子结构,判断一棵二叉树是不是另一个二叉树的子结构
思路:递归进行,使用的是或的操作,需要和子树进行区分

    public static boolean isSubTree(TreeNode root1,TreeNode root2){

        if(root1==null) return false;
        if(root2==null) return true;
        boolean res=false;
        if(root1!=null&&root2!=null){
            if(root1.val==root2.val){
                res=match(root1,root2);
            }
            if(!res){
                res=isSubTree(root1.left,root2);
            }
            if(!res){
                res=isSubTree(root1.right,root2);
            }
        }
        return res;
    }

    public static boolean match(TreeNode root1,TreeNode root2){
        if(root1==null) return false;
        if(root2==null) return true;
        if(root1.val!=root2.val) return false;
        return match(root1.left,root2.left)&&match(root1.right,root2.right);
    }

面试题 19二叉树的镜像

    public static TreeNode mirror(TreeNode root){
        if(root==null) return root;
        TreeNode tmp=mirror(root.left);
        root.left=mirror(root.right);
        root.right=tmp;
    }


面试题 20顺时针打印矩阵

    public static void printMatrx(int [][] a){
        int m=a.length,n=a[0].length;
        int start=0;
        while(start*2<m&&start*2<n){
            helper(a,start);
            start++;
        }
    }

    public static void helper(int [][]a ,int start){
        int endx=a.length-1-start;    //下边界
        int endy=a[0].length-start-1;//右边界

        for(int i=start;i<endy;i++){
            System.out.print(a[start][i]+" ");
        }

        if(start<endx){
            for(int i=start;i<endx;i++){
                System.out.print(a[i][endy]+" ");
            }
        }

        if(start<endx&&start<endy){
            for(int i=endy-1;i>=start;i--){
                System.out.print(a[endx][i]+" ");
            }
        }
        if(start<endy&&start<endx-1){
            for(int i=endx-1;i>=start;i--){
                System.out.print(a[i][start]+" ");
            }
        }   
    }




面试题 21包含min的栈
使用一个辅助栈进行操作,最小栈存放的是数据站对应的最小的元素在数据栈中的位置,而且数量和数据站的数量一致。
    public class {

        Stsck s1=new Stack<>();
        Stsck s2=new Stack<>();

        public static void pushMin(int x){
            if(s1.isEmpty()){
                s1.push(x);
                s2.push(0);
            }
            else{
                int tmp=s1.get(s2.peek());
                if(x<tmp){
                    s2.push(s1.size()-1);
                }
                else{
                    s2.push(s2.peek()); 
                }
            }
        }

        public static void popMin(){
            if(s1.isEmpty()){
                return;
            }
            else{
                s2.pop();
                return s1.pop();
            }
        }

        public static int getMin(){
            if(!s2.isEmpty()){
                return s1.get(s2.peek());
            }
            else {
                return 0;
            }
        }   
    }

//方法二:使用一个栈,如果小于目前的最小值则插2遍
    Stack<Integer> s=new Stack<>();
    int min=Integer.MAX_VALUE;  
    public static void push(int x){
        if(x<=min){
            s.push(min);
            min=x;
        }
        s.push(x);
    }

    public static void pop(){
        if(s.peek()==min){
            s.pop();
            min=s.pop();
        }
        else{
            s.pop();
        }   
    }
    public static getmin(){
        return min;
    }

面试题 22从上往下打印二叉树
二叉树的层次遍历,使用一个队列来存储,

    public static void printTree(TreeNode root){
        if(root==null) return ;
        Queue<TreeNode> q=new LinkedList<TreeNode>();
        q.add(root);
        while(!q.isEmpty()){
            TreeNode node=q.poll();
            System.out.peint(node.val);
            if(node.left!=null){
                q.add(node.left);
            }
            if(q.right!=null){
                q.add(node.right);
            }
        }
    }

    public static List<List<Integer>> level(TreeNode root){
        List<List<Integer>> res=new ArrayList<>();
        if(root==null) return res;
        Queue<TreeNode> q=new LinkedList<TreeNode>();
        q.add(root);
        while(!q.isEmpty()){
            int  n=q.size();
            List<Integer> tmp=new ArrayList<>();
            for(int i=0;i<n;i++){
                TreeNode node=q.remove();
                tmp.add(node.val);
                if(node.left!=null){
                    q.add(node.left);
                }
                if(node.right!=null){
                    q.add(node.right);
                }
            }
            res.add(tmp);
        }
        return res;
    }

面试题 23二叉搜索树的后续遍历序列,判断一个整数数组是不是二叉搜索树的后续遍历结果  
后续遍历是左右中   搜索树特点是是左<中<右 

    public static boolean searchBST(int [] a,int start,int end){
        if(a.length<=0) return false;
        int i=start;
        while(i<end-1&&a[i]<a[end]){
            i++;
        }
        int index=i;
        while(i<end-1&&a[i]>a[end]){
            i++;
        }
        if(i!=end-1) return false;
        return searchBST(a,start,index-1)&&searchBST(a,index,end-1);    
    }

面试题 24二叉树中和为某一值的路径
递归思想 深度优先搜索 

    //判断是否存在
    public static boolean pathSum(TreeNode root,int sum){
        if(root==null) return false;
        if(root.val==sum&&root.left==null&&root.right==null){
            return true;
        }
        return pathSum(root.left,sum-root.val)||pathSum(root.right,sum-root.val);
    }

    //输出所有的,需要用一个容器来保存路径
    int [] save=new save[1000];
    List<List<Integer>> res=new ArrayList<>();
    public static List<List<Integer>> pathsum(TreeNode root,int sum){
        if(root==null) return res;
        helper(root,sum,0);
    }
    public static void helper(TreeNode root,int sum,int index){
        if(root==null) return;
        save[index]=root.val;
        if(root.val==sum&&root.left==null&&root.right==null){
            List<Integer> tmp=new ArrayList<>();
            for(int i=0;i<=index;i++){
                tmp.add(save[i]);
            }
            res.add(tmp);
            return;
        }
        helper(root.left,sum-root.val,index+1);
        helper(root.right,sum-root.val,index+1);
    }

    相关扩展,输出所有的二叉树的路径

    int [] save=new save[1000];
    List<List<Integer>> res=new ArrayList<>();
    public static List<List<Integer>> pathsum(TreeNode root){
        if(root==null) return res;
        helper(root,0);
    }
    public static void helper(TreeNode root,int index){
        if(root==null) return;
        save[index]=root.val;
        if(root.left==null&&root.right==null){
            List<Integer> tmp=new ArrayList<>();
            for(int i=0;i<=index;i++){
                tmp.add(save[i]);
            }
            res.add(tmp);
            return;
        }
        helper(root.left,index+1);
        helper(root.right,index+1);
    }



面试题 27把一个二插搜索树转换成双向链表
中序遍历

    public TreeNode Convert(TreeNode root) {
      if(root==null)
            return null;
        if(root.left==null&&root.right==null)
            return root;
        // 1.将左子树构造成双链表,并返回链表头节点
        TreeNode left = Convert(root.left);
        TreeNode p = left;
        // 2.定位至左子树双链表最后一个节点
        while(p!=null&&p.right!=null){
            p = p.right;
        }
        // 3.如果左子树链表不为空的话,将当前root追加到左子树链表
        if(left!=null){
            p.right = root;
            root.left = p;
        }
        // 4.将右子树构造成双链表,并返回链表头节点
        TreeNode right = Convert(root.right);
        // 5.如果右子树链表不为空的话,将该链表追加到root节点之后
        if(right!=null){
            right.left = root;
            root.right = right;
        }
        return left!=null?left:root;  
    }

面试题 28字符串的排列,不重复的

    public static void Stringpailie(String s){
        if(s.length()<=0) return;
        char [] c=s.toCharArray();
        helper(c,0,c.length-1);

    }
    public static void helper(char [] c,int from ,int to){
        if(to<1||from>c.length) return;
        if(from==to){
            for(int i=0;i<=to;i++){
                System.out.print(c[i]);
            }
            System.out.println();
        }
        for(int i=from;i<=to;i++){
            swap(c,from,i);
            helper(c,from+1,to);
            swap(c,from,i);
        }   
    }

    public static void swap(char [] c,int a,int b){
        char tmp=c[a];
        c[a]=c[b];
        c[b]=tmp;
    }

面试题 29数组中出现此数超过一半的数字
方法一可以使用hash记录出现次数,也可以排序在处理,最好的是使用摩尔投票方法。

    public static int majorityNum(int [] a){
        if(a==null) return -1;
        if(a.length==1) return a[0];
        int times=0;
        int save=0;
        for(int i=0;i<a.length;i++){
            if(times==0){
                save=a[i];
                times=1;
            }
            else if(save==a[i]){
                times++;
            }
            else{
                times--;
            }
        }
        int cnt=0;
        for(int i=0;i<a.length;i++){
            if(a[i]==save) cnt++;
        }
        if(cnt>a.length/2){
            return save;
        }   
    }

扩展:寻找数组中出现次数大于n/3的数,

    public static List<Integer> majorityNum(int [] a){
        List<Integer> res=new ArrayList<>();
        if(a==null) return res;
        //寻找
        int m=0,n=1,cm=0,cn=0;
        for(int i=0;i<a.length;i++){
            if(a[i]==m){
                cm++;
            }
            else if(a[i]==n){
                cn++;
            }
            else if(cm==0){
                m=a[i];
                cm=1;
            }
            else if(cn==0){
                n=a[i];
                cn=1;
            }
            else {
                cm--;cn--;
            }
        }
        //验证
        int cnt1=0,cnt2=0;
        for(int i=0;i<a.length;i++){
            if(a[i]==m) cnt1++;
            if(a[i]==n) cnt2++;
        }

        if(cnt1>a.length/3){
            res.add(m);
        }
        if(cnt2>a.length/3){
            res.add(n);
        }

        return res;     
    }

面试题 30最小的K个数,快排切分思想,使得小于第K个数的都在左侧,大于第K个数的都在右侧
时间复杂度是O(N),也可以使用维护一个小顶堆,用优先队列即可。
//方案1
    public static int[] smallKMum(int [] a,int s){
        int[] res=new int[k];
        if(a==null||k>a.length) return res;
        int left=0,right=a.length-1;
        int index=partition(a,left,right);
        int k=a.length-s;
        while(index!=k-1){
            if(index>k-1){
                index=partition(a,left,index-1);
            }
            else{
                index=partition(a,index+1,right);
            }
        }
        for(int i=0;i<k;i++){
            res[i]=a[i];
        }
        return res; 
    }

    public static int partition(int [] a,int from,int to){
        if(a==null||from>to) return -1;
        int base=a[from];
        while(from<to){
            while(from<to&&a[to]>base){
                to--;
            }
            if(from<to){
                a[from++]=a[to];
            }
            while(from<to&&a[from]<base){
                from++;
            }
            if(from<to){
                a[to--]=a[from];
            }
        }
        a[from]=base;
        return from;        
    }

//方案2
    public static int[] minKMum(int [] a,int k){
        int[] res=new int[k];
        if(a==null||k>a.length) return res;
        Queue<Integer> q=new priorityQueue<>();
        for(int i=0;i<a.length;i++){
            if(q.size()<k){
                q.offer(a[i]);
            }
            else if(a[i]<q.peek()){
                q.poll();
                q.offer(a[i]);
            }
        }
        int i=0;
        while(!q.isEmpty()){
            res[i++]=q.poll();
        }
        return res; 
    }

扩展:找到第K大的数即可    

    public static int bigKMum(int [] a,int from,int to,int k){      
        if(a==null||k>a.length) return -1;
        if(from<=to){
            int index=partition(a,from,to);
            int num=to-index+1;
            if(num==k) return a[num];
            else if(num>k){
                return bigKMum(a,index+1,to,k);
            }
            else{
                return bigKMum(a,from,index-1,k-index);
            }
        }
        return -1;
    }

面试题 31连续子数组的最大和(最大序列和)

    public static int maxSum(int [] a){
        if(a==null) return -1;
        if(a.length==1) return a[0];
        int max=0,sum=0;
        for(int i=0;i<a.length;i++){
            sum=sum+a[i];
            if(sum>max){
                max=sum;
            }
            if(sum<0) sum=0;
        }
        return max;
    }

面试题 321到N的整数中1出现的次数。
数位递归     




面试题 34第K个丑数,规定1是第一个丑数 

    public static int getUglyNum(int k){
        if(k==1) return 1;
        if(k<1) return -1;
        int [] num=new int[k];
        num[0]=1;
        int index=1;
        int p2=0;
        int p3=0;
        int p5=0;
        while(index<k){
            num[index]=min3(num[p2]*2,num[p3]*3,num[p5]*5);
            while(num[p2]*2<=num[index]){
                p2++;
            }
            while(num[p3]*3<=num[index]){
                p3++;
            }
            while(num[p5]*5<=num[index]){
                p5++;
            }
            index++;
        }
        return num[index-1];
    }

    public static int min3(int a,int b,int c){
        int res=a;
        if(res>b) res=b;
        if(res>c) res=c;
        return res;
    }



面试题 35第一个只出现一次的字符
时间复杂度是O(N),使用的是LinkedHashMap

    public static char findOnce(String s){
        char res=' ';
        Map<Character,Integer> m=new LinkedHashMap<>();
        for(int i=0;i<s.length();i++){
            if(m.containsKey(s.charAt(i))){
                m.put(s.charAt(i),-2);
            }
            else{
                m.put(s.charAt(i),i);
            }
        }
        //遍历LinkedHashMap
        Iterator<Entry<Character,Integer>>  ite=m.entrySet().iterator();
        int min=Integer.MAX_VALUE;
        while(ite.hasNext()){
            Entry<Character, Integer> entry = iterator.next();
            if(enter.getValue()>=0&&enter.getValue<min){
                min=entry.getValue;
                res=entry.getKey();
            }  
        }
        return res;
    }

面试题 36数组中的逆序对
使用归并排序实现,求的是数量

    int cnt=0;
    public static int inversPair(int [] a){
        if(a.length<=1) return 0;
        sort(a,o,a.length-1);
    }

    public static void sort(int [] a,int from,int to){
        if(a==null||from>=to) return;
        if(from<to){
            int middle=from+(to-from)/2;
            sort(a,from,middle);
            sort(a,middle+1,to);
            merge(a,from,middle,to);
        }
    }

    public static void merge(int [] a,int from,int middle,int to){
        if(a==null||from>=to) return;
        int[] tmp=new int[to-from+1];
        int i=from,j=middle+1,k=0;
        while(i<=middle&&j<=to){
            if(a[i]<=a[j]){
                tmp[k++]=a[i++];
            }
            else{
                cnt+=j-k;//计算逆序对
                tmp[k++]=a[j++];                
            }
        }
        while(i<=middle){
            tmp[k++]=a[i++];
        }
        while(j<=to){
            tmp[k++]=a[j++];
        }
        for(int i=0;i<k;i++){
            a[from+i]=tmp[i];
        }
    }

面试题 37链表的第一个公共节点
方法是先比较长度,比较长的那个先移位,两个长度一样了再比较

    public static LinstNode commenNode(ListNode head1,ListNode head2){
        if(head1==null||head2==null) return null;
        int m=getLen(head1);
        int n=getLen(head2);
        int diff=Math.abs(m-n);
        while(diff>0){
            if(m>n) head1=head1.next;
            else head2=head2.next;
            diff--;
        }
        while(head1!=null&&head2!=null){
            if(head1==head2){
                return head1;
            }
            else{
                head1=head1.next;
                head2=head2.next;
            }
        }
        return null;
    }

    public static int getLen(ListNode head){
        int res=0;
        LinstNode p=head;
        while(p!=null){
            p=p,next;
            res++;
        }
        return res;
    }

面试题 38目标数字在有序数组中出现的次数
二分查找的变形,找到第一次出现的位置和最后一次出现的位置,然后就可以求出来了  

    public static int getCountK(int[] a,int k){
        if(a==null) return 0;
        int from=getFirst(a,k);
        int to=getLast(a,k);
        System.out.println(from+" "+to);
        if(from>-1&&to>-1){
            return to-from+1;
        }
        else return 0;

    }

    public static int getLast(int[] a,int k){
        if(a==null) return -1;
        int l=0,r=a.length-1;

        while(l<r-1){
            int mid=l+(r-l)/2;
            if(a[mid]>k){
                r=mid-1;
            }
            else l=mid;
        }
        if(a[r]==k) return r;
        else if(a[l]==k) return l;
        return -1;      
    }


    public static int getFirst(int[] a,int k){
        if(a==null) return -1;
        int l=0,r=a.length-1;

        while(l<r-1){
            int mid=l+(r-l)/2;
            if(a[mid]<k){
                l=mid+1;
            }
            else r=mid;
        }
        if(a[l]==k) return l;
        else if(a[r]==k) return r;
        return -1;  
    }

面试题 39二叉树的最大深度  

    public static int maxLen(TreeeNode root){
        if(root==null) return 0;
        return Math.max(maxLen(root.left),maxLen(root.right))+1;
    }

扩展  最小深度

    public static int minLen(TreeeNode root){
        if(root==null) return 0;
        if(root.left==null) return minLen(root.right)+1;
        if(root.right==null) return minLen(root.left)+1;
        return Math.min(minLen(root.left),minLen(root.right))+1;
    }

面试题 40数组中只出现一次的数字
使用异或操作

    public static int findOnly(int[] a){
        if(a.length==1) return a[0];
        int res=0;
        for(int i=0;i<a.length;i++){
            res=res^a[i];
        }
        return res;
    }

    扩展 只出现一次的两个数字,还是使用异或
    public static int[] findOnly(int[] a){
        int[] res=new int[2]; 
        int tmp=0;
        for(int i=0;i<a.length;i++){
            tmp=tmp^a[i];
        }
        int index=helper(tmp);
        int num1=0,num2=0;
        for(int i=0;i<a.length;i++){
            if(((a[i]>>index)&1)==0){
                num1=num1^a[i];
            }
            else{
                num2=num2^a[i];
            }
        }
        res[0]=num1;
        res[1]=num2;
        return res;
    }

    public static int helper(int a){
        int res=0;
        while((a&1)==0){
            res++;
            a=a>>1;
        }
        return res;     
    }

面试题 41数组中和为S的两个数
使用hashmap,

    public static int[] twoSum(int[] a,int sum){
        int[] res=new int[2];
        if(res==null) return res;
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<a.length;i++){
            if(map.get(sum-a[i])!=null){
                res[0]=i;
                res[1]=map.get(sum-a[i]);
            }
            else map.put(a[i],i);
        }
        return res;
    }


面试题 42单词反转 i love you ====>you love i
使用split()

    public static String WordReverse(String s){
        if(s==null) return "";
        String [] save=s.split(" ");
        StringBuffer sb=new StringBuffer();
        for(int i=save.length-1;i>=0;i--){
            if(save[i]!=" "){
                sb.append(save[i]);
                sb.append(" ");
            }
        }
        return sb.length()==0? "":sb.substring(0,sb.length()-1).toString();
    }


扩展 三次翻转法

    public static String WordReverse(String s,int k){
        if(s==null) return "";
        char[] c=s.toCharArray();
        Reverse(c,0,k-1);
        Reverse(c,k,c.length-1);
        Reverse(c,0,c.length-1);
        return String.()
    }

    public static void Reverse(char[] c,int from,int to){
        if(from>=to) return;
        while(from<to){
            char tmp=c[from];
            c[from]=c[to];
            c[to]=tmp;
            from++;to--;
        }
    }

面试题 45圆圈中最后剩下的数字,约瑟夫环

    public static int Reamin(int n,int m){
        if(n<1||m<1) return -1;
        int last=0;
        for(int i=2;i<=n;i++){
            last=(last+m)%i;
        }
        return last;
    }


面试题 47不用加号实现加法,位运算

    public static int plus(int a,int b){
        while(b!=0){
            int c=a^b;
            b=(a&b)<<1;
            a=c;
        }
        return a;
    }

面试题 59判断二叉树是不是镜像二叉树
方法是前序遍历和镜像前序遍历比较

    public static boolean iSMirrorTree(TreeNode root){
        if(root==null) return false;
        return helper(root,root);
    }

    public static boolean helper(TreeNode root1,TreeNode root2){
        if(root1==null&&root2==null) return true;
        if(root1==null||root2==null) return false;
        if(root1.val!=root2.val) return false;
        return helper(root1.left,root2.right)&&helper(root1.right,root2.left);
    }






















  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值