【剑指offer】手撕代码(1)

从本篇开始连续五篇总结《剑指offer》这本书里的50道编程题目,这些题目是在面试中常见被要求手写的,所以一定要很熟悉。另外,这些题目我均用Java来编写,题目中的思想也可以总结出来用在很难的编程题上,要求自己每道至少独立手写三遍 ~

1、实现单例模式

饿汉式单例
class Singleton{
    //先是上来就new属性
    private static final Singleton instance = new Singleton();
    //无参私有构造方法
    private Singleton(){}
    //静态方法
    public static Singleton getInstance(){
        return instance;
    }
    //普通方法
    public void print(){
        System.out.println("Hello World!");
    }
}
懒汉式单例
class Singleton{
    //声明属性
    private static final Singleton instance = null;
    private Singleton(){};
    public static Singleton getInstance(){
        if (instance==null){
            instance = new Singleton();
        }
        return instance;
    }
    public void print(){
        System.out.println("Hello World!");
    }
}

2、二维数组查找

  • 每行从左到右,每列从上到下,依次增大。给定任意二维数组和任意数字,查询数组中是否包含此整数。
public class Test{
    public static boolean findNum(int[][] arr,int number){
        if (arr==null)
            return false;
        int column = arr[0].length-1;
        int row = 0;
        while (row<arr.length && column>=0){
            if (arr[row][column]==number)
                return true;
            if (arr[row][column]>number){
                column--;
            }else {
                row++;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        int[][] arr = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
        System.out.println( findNum(arr,55));
    }
}

3、替换空格

  • 将字符串中的每个空格替换成“%20”
public class Test{
    public static String replaceBlank(String str){
        if (str==null)
            return null;
        StringBuffer sb = new StringBuffer();
        for (int i=0;i<str.length();i++){
            if (str.charAt(i)==' '){
                sb.append("%20");
            }else {
                sb.append(str.charAt(i));
            }
        }
        return new String(sb);
    }
    public static void main(String[] args) {
        System.out.println(replaceBlank("Hello World !"));
    }
}

4、从尾到头打印链表

  • 输入一个链表的头节点,从尾到头打印出每个节点的值
public class Test{
    public static void main(String[] args) {
        ListNode node1 = new ListNode();
        ListNode node2 = new ListNode();
        ListNode node3 = new ListNode();
        node1.data=1;
        node2.data=2;
        node3.data=3;
        node1.next=node2;
        node2.next=node3;
        printListNodeReverse(node1);
    }

//    //非递归实现,用栈
//    public static void printListNodeReverse(ListNode headNode){
//        Stack stack = new Stack();
//        while (headNode!=null){
//            stack.push(headNode);
//            headNode=headNode.next;
//        }
//        while (!stack.isEmpty()){
//            System.out.println(stack.pop().data);
//        }
//    }

    //递归实现
    public static void printListNodeReverse(ListNode headNode) {
        if (headNode!=null){
            if (headNode.next!=null){
                printListNodeReverse(headNode.next);
            }
        }
        System.out.println(headNode.data);
    }
}

5、重建二叉树

  • 给定一颗二叉树的中序和后序遍历结果,重建这棵树,假设都不包含重复数字。例如:前序{1,2,4,7,3,5,6,8} 后序{4,7,2,1,5,3,8,6}
class BinaryTreeNode{
    public static int value;
    public BinaryTreeNode leftNode;
    public BinaryTreeNode rightNode;
}
public class Test{
    public static BinaryTreeNode constructCore(int[] preorder,int[] midorder){
        if (preorder==null || midorder==null)
            return null;
        if (preorder.length!=midorder.length)
            new Exception("前序和中序长度不同,属于非法输入...");
        BinaryTreeNode root = new BinaryTreeNode();
        for (int i=0;i<midorder.length;i++){
            if (midorder[i]==preorder[0]){
                root.value = midorder[i];
                System.out.println(root.value);
                //这个拷贝函数,拷的是前后序号之间的。左闭右开。
                root.leftNode = constructCore(Arrays.copyOfRange(preorder,1,i+1),
                        Arrays.copyOfRange(midorder,0,i));
                root.rightNode = constructCore(Arrays.copyOfRange(preorder,i+1,preorder.length),
                        Arrays.copyOfRange(midorder,i+1,midorder.length));
            }
        }
        return root;
    }

    public static void main(String[] args) {
        int[] pre = {1,2,4,7,3,5,6,8};
        int[] mid = {4,7,2,1,5,3,8,6};
        System.out.println(constructCore(pre,mid));
    }
}

6、用两个栈实现队列

  • 分别实现函数appendTail和deleteHead 尾插和头删,初始栈为空。
public class Test{
    private Stack<Integer> stack1 = new Stack<>();
    private Stack<Integer> stack2 = new Stack<>();
    public void appendTail(Integer a){
        stack1.push(a);
        System.out.println(stack1);
    }
    public Integer deleteHead() throws Exception {
        if (stack2.isEmpty()){
            while (!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        if (stack2.isEmpty()){
            throw new Exception("队列为空,不能删除");
        }
        System.out.println(stack2);
        return stack2.pop();
    }
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        test.appendTail(1);
        test.appendTail(2);
        test.appendTail(3);
        test.deleteHead();
    }
}

7、旋转数组

  • 求一个旋转数组中的最小数字,把一个数组最开始的若干元素搬到数组末尾,成为旋转。输入一个递增排序的数组的旋转。
public class Test{
    public static void main(String[] args) {
        //int[] array = {1,0,1,1,1};
        //int[] array = {3,4,5,1,2};
        int[] array = {1,2,0,1,1};
        System.out.println(Arrays.toString(array));
        System.out.println(findMinNum(array));
    }
    public static Integer findMinNum(int[] arr){
        if (arr==null)
            return null;
        int leftIndex=0;
        int rightIndex=arr.length-1;
        int mid=0;
        //判断是否为旋转过的数组
        while (arr[leftIndex]>=arr[rightIndex]) {    //数组最左边的数>=最右边的数,旋转过的进入循环
            if (rightIndex - leftIndex <= 1) {   //整个数组中只有一个数或者两个数
                mid = rightIndex;     //中间指针赋给任意一个即可
                break;
            }
            mid = (leftIndex + rightIndex) / 2;   //否则,取中间指针为靠前的那个
            // 如果数组左右两数相等并且左边的数等于中间数
            if (arr[leftIndex] == arr[rightIndex] && arr[leftIndex] == arr[mid]) {
                //上述条件下满足:次左和次右的数不相等
                if (arr[leftIndex + 1] != arr[rightIndex - 1]) {
                    //若左边小就取次左赋给中间,右边小就取次右赋给中间
                    mid = arr[leftIndex + 1] < arr[rightIndex - 1] ? (leftIndex + 1) : (rightIndex - 1);
                    break;
                } else {
                    //若次左和次右相等,索引就一起向中间挪步
                    leftIndex++;
                    rightIndex--;
                }
            } else {
                //左右两数不等
                //若中间数大于左数
                if (arr[mid] >= arr[leftIndex])
                    leftIndex = mid;
                else if(arr[mid]<arr[rightIndex]){
                    rightIndex = mid;
                }
            }
        }
        return arr[mid];
    }
}

8、实现快速排序(分治法)

public class Test{
    public static void quickSort(int[] arr,int startIndex,int endIndex){
        if (startIndex>=endIndex)
            return;
        int mid = partition(arr,startIndex,endIndex);
        quickSort(arr,startIndex,mid-1);
        quickSort(arr,mid+1,endIndex);
    }
    private static int partition(int[] arr,int startIndex,int endIndex){
        //取传入数组中的第一个元素为基础数据
        int data = arr[startIndex];
        int left = startIndex;
        int right = endIndex;
        //循环结束条件为左右指针相等时
        while (left!=right){
            //从后向前找小于基础数的数字,如果不是,就继续向前找
            while (left<right && arr[right]>=data)
                right--;
            //从前往后找大于基础数的数字,如果不是,就继续向后找
            while (left<right && arr[left]<=data)
                left++;
            //此时已经找到相应的两个数字,进行交换
            if (left<right){
                int temp = arr[left];
                arr[left] = arr[right];
                arr[right] = temp;
            }
        }
        //此时left和right在相同位置,则把当前指针处的数据与基础数据交换
        int temp = arr[left];
        arr[left] = data;
        arr[startIndex] = temp;
        return left;
    }

    public static void main(String[] args) {
        //int[] arr = new int[]{4,7,6,5,3,2,8,1};
        int[] arr = new int[]{7,6,3,6,0,2,1,4,3};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
 }

9、求出斐波那契数列的第n项

public class Test{
    public static long fibnacci(int n){
        long result = 0;
        long preOne = 0;
        long preTwo = 1;
        if (n==0)
            return preOne;
        if (n==1)
            return preTwo;
        for(int i=0;i<n;i++){
            result=preOne+preTwo;
            preOne = preTwo;
            preTwo = result;
        }
        return result;
    }
    public static void main(String[] args) {
        System.out.println(fibnacci(5));
    }
}

10、求二进制数中1的个数

public class Test{
    public static int numOf_1(int n){
        int count = 0;
        while (n!=0){
            count++;
            n=n&(n-1);
        }
        return count;
    }
    public static void main(String[] args) {
        System.out.println(numOf_1(15));
    }
}

你可能感兴趣的:(题目)