zoukankan      html  css  js  c++  java
  • 笔试题目汇总

     

    一、已知数组A[],实现数组B[];使得B[i]=A[0]*A[1]...*A[i-1]*A[i+1]...*A[n-1]
    要求:
    1)不能使用除法
    2)时间复杂度为O(n)
    3)空间复杂度为O(1)

    package com.bobo.interview;
    
    public class Yahoo1 {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
        }
    
        // 1,已知数组A[],实现数组B[];使得B[i]=A[0]*A[1]...*A[i-1]*A[i+1]...*A[n-1]
        // 要求:
        // 1)不能使用除法
        // 2)时间复杂度为O(n)
        // 3)空间复杂度为O(1)
        public int[] calResult(int[] a) {
            int length=a.length;
            int[] b=new int[length];
            b[0]=1;
            //经过这轮循环之后,b[i]中各个元素的值,等于对应位置之前的元素的乘积
            //每一个都是先通过b[0](因为b[0]相当于无用,因此可以作为中转)算出来,然后再赋值给对应的b[i]
            for(int i=1;i<length;i++){
                b[0]*=a[i-1];
                b[i]=b[0];
            }
            b[0]=1;
            //之后从后往前扫描
            //经过这次之后,最终的结果就是除了其本身之外,所有元素的乘积
            for(int i=length-2;i>0;i--){
                //该元素之后所有元素的乘积
                b[0]*=a[i+1];
                //之前的元素乘以之后的元素即可
                b[i]*=b[0];
            }
            return b;
        }
    
    }
    问题解答

    二、4k+2个数字,k个数出现4次,一个数字出现2次。找到出现1次的这个数字。并衡量其空间和时间复杂度。

    方法一:最常见的思路:利用hashMap统计频次,

    显然,这种方法是最low的,是一般的频次统计方法,没有充分利用出现次数非4即2的信息。

    方法二:

    使用一个32位的int数组记录每一位出现的次数,如果出现次数等于4则重置为0;如果一个数字出现4次,那么该数字对于该int数组的贡献就为0;因此余下的就是出现2次的数字。

    代码如下:

    package com.bobo.interview;
    
    public class Yahoo1 {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            int array[] = { 3, 3, 3, 3, 5, 5, 5, 5, 7, 7 };
            System.out.println(findNumAppearTwoTimes(array) + "");
    
        }
    
        // http://wenku.baidu.com/link?url=0oBsX_5yqMA4h2nWkmWDWMOSpTe2cq0b7Z3lPFu7lwvTfQIDcm0LrZuqHvu4ouYQO8MamkNd3B5esY3_ECvhxiUd0Iqzn8RCj-0imz0ecO7
        // 1,已知数组A[],实现数组B[];使得B[i]=A[0]*A[1]...*A[i-1]*A[i+1]...*A[n-1]
        // 要求:
        // 1)不能使用除法
        // 2)时间复杂度为O(n)
        // 3)空间复杂度为O(1)
        public int[] calResult(int[] a) {
            int length = a.length;
            int[] b = new int[length];
            b[0] = 1;
            // 经过这轮循环之后,b[i]中各个元素的值,等于对应位置之前的元素的乘积
            // 每一个都是先通过b[0](因为b[0]相当于无用,因此可以作为中转)算出来,然后再赋值给对应的b[i]
            for (int i = 1; i < length; i++) {
                b[0] *= a[i - 1];
                b[i] = b[0];
            }
            b[0] = 1;
            // 之后从后往前扫描
            // 经过这次之后,最终的结果就是除了其本身之外,所有元素的乘积
            for (int i = length - 2; i > 0; i--) {
                // 该元素之后所有元素的乘积
                b[0] *= a[i + 1];
                // 之前的元素乘以之后的元素即可
                b[i] *= b[0];
            }
            return b;
        }
    
        // 4k+2个数字,k个数出现4次,一个数出现两次,编写代码,找到这两个出现两次的数字
        public static int findNumAppearTwoTimes(int[] array) {
            // 记录每一位出现的次数
            int bit_count[] = new int[32];
            for (int i = 0; i < array.length; i++) {
                for (int j = 0; j < 32; j++) {
                    if ((array[i] & (1 << j)) != 0) {
                        bit_count[j]++;
                    }
                    // 如果对应位置等于4,那么重新置为0;这样的话,出现4次的数字对bit_count的贡献就可以忽略了
                    if (bit_count[j] == 4) {
                        bit_count[j] = 0;
                    }
                }
            }
            int result = 0;
            for (int i = 0; i < 32; i++) {
                // 记好了,关于2的幂运算,都可以通过移位来实现的!!!
                if (bit_count[i] == 2) {
                    result += (1 << i);
                }
            }
            return result;
        }
    
        // 矩阵中的元素查找问题,二分查找的矩阵版
        // 给定一个M*N的二维矩阵,每行、每列的元素都是从小到大有序的;要求设计一个算法,在该矩阵中快速寻找给定的值。
        // 自己的误解:首先对行进行二分查找,之后对列进行二分查找,但这是错误的
        // 1 3 7 15 16
        // 2 5 8 18 19
        // 4 6 9 22 23
        // 10 13 17 24 28
        // 20 21 25 26 33
        // 如在这个矩阵中查找10,按照上面的思路进行查找,就会得到false的结果,显然是错误的
    
        // 正确的思路是:
        // 方法一:上述误解是先对行再对列,进行列进行查找,这就启发我们尝试遍历对角线
        // 从左上角开始,遍历对角线有个好处,每次可以排除一行(对角线元素<target)或者一列(对角线元素>target)
        // 假设目标是10,从右上角开始,由于16>10,那么排除16所在的列,之后再第一行的1到15之间进行查找,没有找到;因此走到下一个对角线元素18,18依旧>10;因此继续在第二行的2到8之间查找,没有找到;走到下一个对角线元素9,而9<10,因此排除9所在的行
        // 这种方法每次排除一行或者一列,因此时间复杂度为O(n的平方)
        public boolean findNumInMetrix(int[][] metrix, int target) {
            int row = 0;
            int column = metrix[0].length;
            while (row < metrix.length && column >= 0) {
                if (metrix[row][column] > target) {
                    column--;
                } else if (metrix[row][column] < target) {
                    row++;
                } else {
                    return true;
                }
                // 之后在对应行或者列进行二分查找
                if (binarySearch(metrix[row], 0, column, target)) {
                    return true;
                }
            }
            return false;
        }
    
        private boolean binarySearch(int[] array, int start, int end, int target) {
            int low = start;
            int high = end;
            int middle = (low + high) / 2;
            while (low <= high) {
                if (array[middle] < target) {
                    high = middle - 1;
                } else if (array[middle] > target) {
                    low = middle + 1;
                } else {
                    return true;
                }
            }
            return false;
    
        }
    }
    4k+2问题

    进一步思考

    一:其实这个int数组记录的只有0,1,2,3这么4中情况,利用一个int来计数其实有浪费,仅使用两个bit就可以记录这4中状态(代码略)。

    二:如果一个数字出现了6次,就和出现2次的弄混了。不过因为题目中的数字要么出现4次,要么出现2次,因为这种情况可以忽略了。

    三、矩阵元素查找

      给定一个M*N的二维矩阵,每行、每列的元素都是从小到大有序的;要求设计一个算法,在该矩阵中快速寻找给定的值。
    题目分析:自己的误解:首先对行进行二分查找,之后对列进行二分查找,但这是错误的

    1 3 7 15 16
     2 5 8 18 19
    4 6 9 22 23
     10 13 17 24 28
     20 21 25 26 33
    // 如在这个矩阵中查找10,按照上面的思路进行查找,就会得到false的结果,显然是错误的

    // 正确的思路是:
    // 方法一:上述误解是先对行再对列,进行列进行查找,这就启发我们尝试遍历对角线 

    遍历对角线该从哪个地方开始遍历呢,其实只能是右上角(16)和左下角(20);因为右上角是行最大,列最小;而左下角是行最小,列最大。这样就保证了每次可以排除一行或者一列

        // 矩阵中的元素查找问题,二分查找的矩阵版
        // 给定一个M*N的二维矩阵,每行、每列的元素都是从小到大有序的;要求设计一个算法,在该矩阵中快速寻找给定的值。
        // 自己的误解:首先对行进行二分查找,之后对列进行二分查找,但这是错误的
        // 1 3 7 15 16
        // 2 5 8 18 19
        // 4 6 9 22 23
        // 10 13 17 24 28
        // 20 21 25 26 33
        // 如在这个矩阵中查找10,按照上面的思路进行查找,就会得到false的结果,显然是错误的
    
        // 正确的思路是:
        // 方法一:上述误解是先对行再对列,进行列进行查找,这就启发我们尝试遍历对角线
        // 从左上角开始,遍历对角线有个好处,每次可以排除一行(对角线元素<target)或者一列(对角线元素>target)
        // 假设目标是10,从右上角开始,由于16>10,那么排除16所在的列,因此走到下一个对角线元素18,18依旧>10;因此继续在第二行的2到8之间查找,没有找到;走到下一个对角线元素9,而9<10,因此排除9所在的行
        // 这种方法每次排除一行或者一列,因此时间复杂度为O(n的平方)
        public static boolean findNumInMetrix(int[][] metrix, int target) {
            int row = 0;
            int column = metrix[0].length-1;
            while (row < metrix.length && column >= 0) {
                if (metrix[row][column] == target) {
                    return true;
                } else if (metrix[row][column] > target) {
                    column--;
                } else if (metrix[row][column] < target) {
                    row++;
                }
            }
    
            return false;
        }
    矩阵中查找元素

    四,递归到非递归的实现

    快速排序的非递归实现

    void quickSort(int* array,int start,int end){
            if(start>=end){
                    return;
            }
            stack<int> myStack;
            int mid=partation(array,start,end);
            if(start<mid-1){
                    myStack.push(start);
                    myStack.push(mid-1);
            }
            if(end>mid+1){
                    myStack.push(mid+1);
                    myStack.push(end);
            }
            while(!stack.empty()){
                    int high=myStack.top();
                    myStack.pop();
                    int low=myStack.top();
                    myStack.pop();
                    mid=partation(array,low,high);
                    if(low<mid-1){
                            myStack.push(low);
                            myStack.push(mid-1);
                    }
                    if(high>mid+1){
                            myStack.push(mid+1);
                            myStack.push(high);
                    }
            }
    }
    快排非递归

    五,两个栈的特殊使用 

    1,实现一个栈结构,从其中取得栈的最小值,要求时间复杂度为O(1),空间复杂度不要求

    #include<iostream>
    #include<stack>
    using namespace std;
    class minStack{
    private:
            stack<int> myStack;
            stack<int> helpStack;
    public:
            void pop();
            void push(int i);
            int top();
            int getMin();
    };
    
    void minStack::pop(){
            if(!myStack.empty()&&!helpStack.empty()){
                    myStack.pop();
                    helpStack.pop();
            }
    }
    
    void minStack::push(int i){
            myStack.push(i);
            if(helpStack.empty()){
                    helpStack.push(i);
                    return;
            }
            int top=helpStack.top();
            if(top<i){
                    helpStack.push(top);
            }else{
                    helpStack.push(i);
            }
    
    }
    
    int minStack::top(){
            if(!myStack.empty()){
                    return myStack.top();
            }
    }
    
    int minStack::getMin(){
            if(!helpStack.empty()){
                    return helpStack.top();
            }
    }
    
    
    int main(){
            minStack test;
            test.push(2);
            test.push(1);
            test.push(3);
            cout<<test.top();
            cout<<test.getMin()<<endl;
    }
    栈中取最小值,时间复杂度O(1)
  • 相关阅读:
    Linux systemctl 命令完全指南
    分享一些 Kafka 消费数据的小经验
    大数据日志采集系统
    使用Spring Boot Actuator将指标导出到InfluxDB和Prometheus
    这可能是最为详细的Docker入门吐血总结
    用不用lambda,这是一个问题
    es上的的Watcher示例
    Elasticsearch6.5.2 X-pack破解及安装教程
    oauth2.0通过JdbcClientDetailsService从数据库读取相应的配置
    Apache Beam实战指南 | 手把手教你玩转大数据存储HdfsIO
  • 原文地址:https://www.cnblogs.com/bobodeboke/p/3986470.html
Copyright © 2011-2022 走看看