程序员面试题(C++ 实现) - Day2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34719188/article/details/83987303

说明


  • 以下题目均来自于牛客网
  • 以下代码用 C++11 编写
  • 以下代码均已编译通过(Compile by MINGW)
  • 以下代码均有测试案例(Main function)
  • 以下代码均已进行优化或部分优化(Optimize)
  • 以下代码均有注释(Comment)
  • 部分题目附有解析(Analysis)
  • 如有错误或侵权,请联系博主

今日题目一览


  1. 旋转数组的最小数字
  2. 斐波那契数列
  3. 跳台阶(变态跳台阶)
  4. 矩形覆盖
  5. 二进制中 1 的个数

1. 旋转数组中的最小数字


问题描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

解析

该问题是二分搜索的另一种变相形式,设定 low、mid、high,

  • 当 val_mid > val_high 时,说明最小的数字存在于[mid + 1, high]区间(注意不是存在于[mid, high]区间),然后执行 low = mid + 1;
  • 当 val_mid == val_high 时,说明最小的数字存在于[low, high - 1]区间(注意不是存在于[low, mid]区间),然后执行 high --;
  • 当 val_mid < val_high 时,说明最小的数字存在于[low, mid]区间(注意不是存在于[low, mid - 1]区间),然后执行 high = mid;

实现

/*
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
 */

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int minNumberInRotateArray1(vector<int> rotateArray) {
    sort(rotateArray.begin(), rotateArray.end());
    return rotateArray[0];
}

int minNumberInRotateArray2(vector<int> array) {
    int low = 0 ;
    int high = array.size() - 1;
    while(low < high) {
        int mid = low + (high - low) / 2;
        if(array[mid] > array[high]) {
            low = mid + 1;
        } else if(array[mid] == array[high]) {  //这步是关键
            high = high - 1;
        } else {
            high = mid;
        }
    }
    return array[low];
}

int main(int argc, char const *argv[]) {
    //Test
    std::vector<int> v;
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);
    v.push_back(1);
    v.push_back(2);

    cout << minNumberInRotateArray1(v) << endl;
    cout << minNumberInRotateArray2(v) << endl;

    return 0;
}

输出结果

1
1

2. 斐波那契数列


问题描述

输出斐波那契数列的第 n 项(从0开始,第0项为0)。斐波那契数列:0 1 1 2 3 5 8 13 21 34 …

解析

这个主要是迭代算法的理解与应用,知道 f(n) = f(n - 1) + f(n - 2)即可,更多请参考:

Fibonacci 斐波那契数列的几种写法、时间复杂度对比

实现

/*
输出斐波那契数列的第 n 项(从0开始,第0项为0)
斐波那契数列:0 1 1 2 3 5 8 13 ...
 */

#include <iostream>

using namespace std;

// 方法一
int Fibonacci1(int n) {
    if(n == 0)
        return 0;

    if(n == 1)
        return 1;

    int a = 0, b = 1;
    int m = 0;
    int i;

    for(i = 2; i <= n; i++) {  // a + b = m
        m = a + b;
        a = b;
        b = m;
    }
    return m;
}

// 方法二
int Fibonacci2(int n) {
    int result[3] = {0, 1, 1};
    if (n <= 2)
        return result[n];
    return Fibonacci2(n - 1) + Fibonacci2(n - 2);
}

int main(int argc, char const *argv[]) {
    // Test
    for(int i = 0; i < 20; i++)  // 从 1 开始
        cout << Fibonacci1(i) << " ";

    cout << "\n-----------------\n";

    for(int i = 0; i < 20; i++)  // 从 0 开始
        cout << Fibonacci2(i) << " ";

    return 0;
}

输出结果

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 
-----------------
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181

3. 跳台阶(变态跳台阶)


问题描述

跳台阶:一只青蛙一次可以跳 1 级台阶,也可以跳 2 级。求该青蛙跳上一个 n 级台阶总共有多少种跳法(先后次序不同算不同的结果)。

变态跳台阶:一只青蛙一次可以跳 1 级台阶,也可以跳上 2 级……它也可以跳 n 级
求该青蛙跳上一个 n 级的台阶总共有多少种跳法?

解析

参考博客:牛客网——跳台阶和变态跳台阶问题

参考博客:程序员面试100题之二:跳台阶问题(变态跳台阶)

跳台阶(2 种思路):

方法一

这种问题一般是有规律的,跳1级台阶,只有1种方法;跳2级台阶,有2种方法;跳2级台阶,有3种方法;跳4级台阶,有5种方法,依次下去,跳一个n级的台阶的方法数是跳n-1级台阶的方法数与跳n-2阶台阶的方法数的总和。这种思路可以用逆推去想,要跳上一个n级台阶,可以从n-1级台阶跳1级,也可以从n-2级台阶跳2级,这就相当于跳上n-1级台阶的方法加上跳上n-2级台阶的方法。

方法二

这算算法的思路还是和上面的一样,只不过在在写法上显得更为简洁,主要看代码注释。

实现(跳台阶)

/*
一只青蛙一次可以跳 1 级台阶,也可以跳 2 级。
求该青蛙跳上一个 n 级台阶总共有多少种跳法(先后次序不同算不同的结果)。
 */

#include <iostream>

using namespace std;

// 方法一
// 和上面的斐波那契数列一样

// 方法二
int jumpFloor(int n) {
    int f = 1, g = 2;  // 定义了斐波那契数列的第二项和第三项
    n--;
    while(n--) { // 这个循环实现了 g 的递加和 f 的重置,细细写写就知道了
        g += f;
        f = g - f;  // 先加后减就实现了 f 变为原来 g 的值
    }
    return f;
}

int main(int argc, char const *argv[]) {
    //Test
    //eg: 跳三层方法有: 111 - 12 - 21
    cout << jumpFloor(3) << endl;
    //eg: 跳五层方法有: 1111 - 121 - 112 - 211 - 22
    cout << jumpFloor(4) << endl;

    return 0;
}

输出结果

3
5

变态跳台阶

可以用逆推的思路去想,跳n级台阶,可以从n-1级跳上来,也可以从n-2级跳上来,从n-3级跳上来,依次下去,从第1级跳上去,或直接跳上去,所以,跳n级台阶的方法数相当于其它所有台阶数的方法的总和再加上从0级跳上去,表达式为 f(n) = f(n-1) + f(n-2) +…+ f(2) + f(1) + 1。例如:

当跳1级台阶时,f(1) = 1;
当跳2级台阶时,f(2) = f(1) + 1 = 2;
当跳3级台阶时,f(3) = f(2) + f(1) + 1 = 4;
当跳4级台阶时,f(4) = f(3) + f(2) + f(1) + 1 = 8;

f(n) = f(n-1) + f(n-2) +…+ f(2) + f(1) + 1
f(n-1) = f(n-2) +…+ f(2) + f(1) + 1
推:f(n) - f(n-1) = f(n-1)
推:f(n) = 2 * f(n-1)

实现(变态跳台阶)

/*
一只青蛙一次可以跳 1 级台阶,也可以跳上 2 级……它也可以跳 n 级
求该青蛙跳上一个 n 级的台阶总共有多少种跳法
 */

#include <iostream>

using namespace std;

int jumpFloorII(int number) {
    if(number == 0)
        return number;
    int total = 1;
    for(int i = 1; i < number; i++)
        total *= 2;
    return total;
}

int main(int argc, char const *argv[]) {
    //Test
    //eg: 跳三层方法有: 111 - 12 - 21 - 3
    cout << jumpFloorII(3) << endl;

    return 0;
}

输出结果

4

4. 矩形覆盖


问题描述

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。
请问用n个2
1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

解析

依旧是斐波那契数列(主要是考察问题的转换能力)

实现

/*
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。
请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
 */

#include <iostream>

using namespace std;

int rectCover(int number) {
    if (number <= 0) {
        return number;
    }
    int f1 = 1;
    int f2 = 2;
    int f3;

    for (int i = 3; i <= number; i++) {
        f3 = f1 + f2;
        f1 = f2;
        f2 = f3;
    }
    return f3;
}

int main(int argc, char const *argv[]) {
    //Test
    //...
    return 0;
}

输出结果

// 没有输出

5. 二进制中 1 的个数


问题描述

输入一个整数,输出该数二进制表示中 1 的个数。其中负数用补码表示。

解析

用 & 位运算符的性质

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

实现

/*
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
 */

#include <iostream>

using namespace std;

int NumberOf1(int n) {
    int count = 0;
    unsigned int flag = 1;
    while(flag) {
        if (n & flag) {
            count++;
        }
        flag = flag << 1;
    }
    return count;
}

int main(int argc, char const *argv[]) {
    //Test
    int m = 10;  // 1010
    cout << NumberOf1(m) << endl;
    int n = 11;  // 1011
    cout << NumberOf1(n) << endl;
    int p = 12;  // 1100
    cout << NumberOf1(p) << endl;
    return 0;
}

输出结果

2
3
2

联系博主


邮箱:[email protected]

猜你喜欢

转载自blog.csdn.net/qq_34719188/article/details/83987303