zoukankan      html  css  js  c++  java
  • 面试常考编程题

    1.   给定一个数组,求最大的连续子序列和,O(n)时间与O(1)空间

    2.   有一个坐标轴,上面有很多点,每个点有坐标,求长度为L的绳子最多能够覆盖几个点。

        两个指针,start,end。 
        如果points[front]-points[rear]<=L,头start向前移动一步。 
        如果points[front]-points[rear]>L,尾巴end向前移动一步。 
        每个数最多遍历2遍,因此时间复杂度为O(n)。 

    int maxCover(int* a, int n, int l)
     5 {
     6     int maxCover = 1;
     7     int begin = 0;
     8     int end = 1;
     9     while(end < n)
    10     {
    11         if(a[end] - a[begin] > l)
    12         {
    13             maxCover = (end - begin) > maxCover?(end - begin):maxCover;
    14             begin++;
    15         }
    16         else
    17             end++;
    18     }
    19     return maxCover;
    20 }

    3.   求一个数组中第k 大的数

    4.   最长公共序列

          

    class LCS {
    public:
        int findLCS(string A, int n, string B, int m) {
            // write code here
            int dp[n + 1][m + 1];
            for(int i = 0; i <= n; i++){
                dp[i][0] = 0;
            }
            for(int j = 0; j <= m; j++){
                dp[0][j] = 0;
            }
            
            for (int i = 0; i < n; i++){
                for (int j = 0; j < m; j++){
                    if (A[i] == B[j]){
                        dp[i + 1][j + 1] = dp[i][j] + 1;
                    }
                    else{
                        dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);
                    }
                }
            }
            return dp[n][m];
        }
    };

     

    5.   最长递增子序列(Longest Increasing Subsequence)是指找到一个给定序列的最长子序列的长度,使得子序列中的所有元素单调递增。

          例如:{ 3,5,7,1,2,8 } 的 LIS 是 { 3,5,7,8 },长度为 4。

    思路:建立一个大小与 nums 长度相等的数组dp,用于记录每个 子序列的 最长长度,即 dp[i] 表示nums 第 0 个到第 i 个元素中以 nums[i]为最大值的最长子序列长度(注意序列的最后一个值为 nums[i]):

    感觉底下的这个图不对。。

          

    //  状态转移方程    dp[i] = max{dp[j]+1,dp[i]}, j<i && a[j]<a[i].
    
    class Solution {
    public://动态规划。时间复杂度为O(n^2)。
        int lengthOfLIS(vector<int>& nums) {
            int n = nums.size();
            if(n <= 1) return n;
            vector<int> dp(n, 1);                   // 初始化为1
            for(int i = 1; i < n; i++){             //dp[i]表示LIS的长度。nums[i]作为LIS的最后一个元素。
                for(int j = 0;j < i; j++)
                {
                    if(nums[i] > nums[j])
                    {                                 //满足递增
                        dp[i]=max(dp[i], dp[j] + 1);  //利用状态转移方程
                    }
                }
            }
            int res=0;
            for(int i = 0;i < n; i++)
            {//求得最大的dp[i]
                res = max(res, dp[i]);
            }
            return res;
        }
    };
    • 使用一个数组h[],其中h[i]表示原数组以arr[i]结尾的最长递增子序列的长度
    • 从i=0到i=n-1过程重复进行n次,求得h=[1,1,2,1,3,2,4,3]。求h[i]的时候,需要考察那些比i小的j,如果arr[i]>arr[j],那么h[i]至少应为h[j]+1,这样对前边的遍历之后即可知道h[i]。
    • h的各个元素求得之后,遍历一遍求最大即可。

          

    6.   连续子数组的最大和

     附加问题:只用加法实现1+2+3+...+n,

    (循环、判断语句也不用)

    1、利用递归来代替循环结构;
    2、利用&&与运算的特性来代替if结构。

    int add(int n, int &sum)    
    {    
        n && add(n-1, sum);    
        return (sum += n);    
    }    

    7.    问题一: 位运算实现加法

    位的异或运算求'和'的结果一致:

    异或 1^1=0 1^0=1 0^0=0

    求和 1+1=0 1+0=1 0+0=0

    位的与运算求'进位‘的结果一致:

    位与 1&1=1 1&0=0 0&0=0

    进位 1+1=1 1+0=0 0+0=0

    于是我们决定用异或运算和与运算来表示加法。

    int add(int a, int b) //递归形式  
    {  
        if(b==0) //递归结束条件:如果右加数为0,即不再有进位了,则结束。  
            return a;  
        int s = a^b;  
        int c = (a&b)<<1; //进位左移1位,达到进位的目的。  
        return add(s, c); //再把'和'和'进位'相加。递归实现。  
    }  

     8.   问题二: 位运算实现减法

       减法其实是用加法来实现的。在ALU中,当我求a-b,其实是求[a-b]补。因为有[a-b]补=[a]补 - [b]补= [a]补+[-b]补。所以我就要先求出-b。求一个数的负的操作是将其连符号位一起取反然后加1。

       于是有办法做减法了:先把减数求负,然后做加法

    int negtive(int i)  
    {  
        return add(~i, 1);  
    }  
    
    int subtraction(int a, int b) //减法运算:利用求负操作和加法操作  
    {  
        return add(a, negtive(b));  
    }  

    9.  问题三: 位运算实现乘法

    乘法操作时即使用补码也要需要考虑符号位了,所以我要先把符号拿出来单独计算。为了方便,先引入两个工具函数,

    int getsign(int i) //取一个数的符号,看是正还是负  
    {  
        return (i>>31);  
    }  
      
    int bepositive(int i) //将一个数变为正数,如果本来就是正,则不变;如果是负,则变为相反数。注意对于-2147483648,求负会溢出。  
    {  
        if(i>>31)  
            return negtive(i);  
        else  
            return i;  
    }  

    循环加法替代乘法。a*b,就是把a累加b次。时间复杂度为O(N)。

    int multiply(int a, int b)  
    {  
        bool flag = true;  
        if(getsign(a) == getsign(b)) //积的符号判定  
            flag = false;  
      
        a = bepositive(a);//先把乘数和被乘数变为正数  
        b = bepositive(b);  
        int ans = 0;  
        while(b)  
        {  
            ans = add(ans, a);  
            b = subtraction(b, 1);  
        }  
      
        if(flag)  
            ans = negtive(ans);  
        return ans;  
    }  

    思路二:

    在二进制数上做乘法,如下图:

    这一过程就是根据乘数的每一位为0或1时,将被乘数错位的加在积上。时间复杂度为O(logN)。

    int multiply(int a, int b)  
    {  
        bool flag = true;  
        if(getsign(a) == getsign(b)) //积的符号判定  
            flag = false;  
      
        a = bepositive(a);  
        b = bepositive(b);  
        int ans = 0;  
        while(b)  
        {  
            if(b&1)  
                ans = add(ans, a);  
            a = (a<<1); //把a错位加在积上  
            b = (b>>1); //从最低位开始依次判断b的每一位  
        }  
      
        if(flag)  
            ans = negtive(ans);  
        return ans;  
    }  

    72. Edit Distance

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

    You have the following 3 operations permitted on a word:

    a) Insert a character
    b) Delete a character
    c) Replace a character

    public class Solution {
        public int minDistance(String word1, String word2) {
            int m = word1.length(), n = word2.length();
            int[][] dp = new int[m + 1][n + 1];
            // 初始化空字符串的情况
            for(int i = 1; i <= m; i++){
                dp[i][0] = i;
            }
            for(int i = 1; i <= n; i++){
                dp[0][i] = i;
            }
            for(int i = 1; i <= m; i++){
                for(int j = 1; j <= n; j++){
                    // 增加操作:str1a变成str2后再加上b,得到str2b 需要的次数
                    int insertion = dp[i][j-1] + 1;
                    // 删除操作:str1a删除a后,再由str1变为str2b  需要的次数
                    int deletion = dp[i-1][j] + 1;
                    // 替换操作:先由str1变为str2,然后str1a的a替换为b,得到str2b  需要的次数(需要先判断是否相等,相等的话加0,不相等就加1)
                    int replace = dp[i-1][j-1] + (word1.charAt(i - 1) == word2.charAt(j - 1) ? 0 : 1);
                    // 三者中取最小的一个操作作为当前的dp
                    dp[i][j] = Math.min(replace, Math.min(insertion, deletion));   
                }
            }
            return dp[m][n];
        }
    }
     
  • 相关阅读:
    强化学习_PolicyGradient(策略梯度)_代码解析
    leetcode_1053. Previous Permutation With One Swap
    leetcode_1052. Grumpy Bookstore Owner
    Tensorflow_入门学习_2_一个神经网络栗子
    通过批处理快速设置IP
    汇编、编译、反汇编、反编译的简单概念介绍
    Logistic回归
    基于概率论的分类方法:朴素贝叶斯
    决策树 预测隐形眼镜类型
    k-近邻算法2(kNN)手写识别系统
  • 原文地址:https://www.cnblogs.com/simplepaul/p/7688707.html
Copyright © 2011-2022 走看看