算法笔记:乱七八糟的题目汇总

一、《剑指offer》面试题三中的题目二:不修改数组找出数组中重复的数字

在一个长度为n+1的数组 nums 里的所有数字都在0~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。
 例如,如果输入长度为8的数组{2, 3, 5, 4, 3, 2, 6, 7},那么对应的输出是重复的数字2或3。

作者介绍了二分法来解决这个问题,简单说,就是把1~n从中间的数字m分成两部分,如果前半部分包含的数字超过m,说明该区间内一定有至少一个重复数字,则继续对这个区间进行二分,后面的区间就不用管了。否则,后半部分区间一定包含重复数字,对它继续进行二分和判断。

如此循环,直到区间范围只能容忍一个数字,且该数字的出现次数大于1,则它一定是重复的。

代码如下。

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int length = nums.size();
        int begin = 0;
        int end = length - 1;
        while (end >= begin) {
            int middle = ((begin + end) >> 2) + begin;
            int count = countnum(nums, begin, middle, length); //搜索在这个范围内的数的个数
            if (begin == middle) { //如果区间最小的元素与区间最大的元素相等,说明该区间只有一个元素
                if (count > 1) //如果这个元素出现次数超过1次说明它重复
                    return begin;
                else //否则,说明这个数组中没有重复元素
                    return -1;
            }

            if (count > middle - begin + 1) //如果这个区间的数出现的次数超过了区间范围,说明区间里肯定有某个数重复
                end = middle;
            else //否则,要遍历紧邻着该区间之后的下一个区间,区间元素的范围是相同的
                begin = middle + 1;           
        }
        return -1;
    }
    int countnum(vector<int> nums, int begin, int end, int length) {
        int count = 0;
        for(auto a : nums)
            if (a <= end && a >= begin)
                count++;
        return count;
    }
};

二、《剑指offer》面试题四:*二维数组中的查找

在一个n*m的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:有矩阵如下。
1 2 8  9
2 4 9  12
4 7 10 13
6 8 11 15
给定查找数字7,则返回true;给定查找数字5,则返回false。

从最右上角的数字开始。如果目标数字小于右上角的数字,则它肯定比这一列的所有数字都小,则不再考虑这一列,查找的范围排除掉这一列,否则不做改变。再查看第一行,如果第一行的倒数第二个数字(倒数第一个数字已经被排除掉了,不再考虑它)小于目标数字,说明这一行所有数字都比目标数字小,则不再考虑第一行,否则不做改变。

第二次循环也同理,让当前的范围内右上角的数字与目标数字比较,缩小行和列的范围。如此循环直到找到数组或找不到数字,返回true或false。

class Solution {
public:
    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
        int rows = matrix.size();   //数组的行数
        if (rows == 0)  //说明数组为空
            return false;

        int cols = matrix[0].size();    //数组的列数
        
        //从右上角开始遍历
        int col = cols - 1; 
        int row = 0;
        while (row < rows && col >= 0) {
            if (target == matrix[row][col])
                return true;
            else if (target < matrix[row][col])
                col--;
            else if (target > matrix[row][col])
                row++;
        }
        return false;
    }
};

三、《剑指offer》面试题63:股票的最大利润

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?
示例1:
 输入: [7,1,5,3,6,4]
 输出: 5
 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例2:
 输入: [7,6,4,3,1]
 输出: 0
 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

面试的时候真的被问到这个题目了,特此记录一下。首先新建一个数组min。遍历给定的prices数组。

如果数组min为空或prices[i]小于数组的最后一个数字,就把prices[i]也加入到数组min中,因此就得到了一个递减的数列。否则,就说明prices[i]比当前的min最后的数字要大,用prices[i]减去数组min的最后一个数字,也就是在prices[i]之前出现过的最小的数字。

代码如下。

#include <stdio.h>

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int min[prices.size()];
        int max_profit = 0;
        int j = 0;
        for (int i = 0; i < prices.size(); i++) {
            if (j == 0 || prices[i] < min[j - 1]) {
                min[j] = prices[i];
                j++;
            }
            else {
                int profit = prices[i] - min[j - 1];
                max_profit = max_profit > profit ? max_profit : profit;
            }
        }
        return max_profit;
    }
};

四、Leetcode332:零钱兑换

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
示例 1:
 输入:coins = [1, 2, 5], amount = 11
 输出:3
 解释:11 = 5 + 5 + 1
示例 2:
 输入:coins = [2], amount = 3
 输出:-1
示例 3:
 输入:coins = [1], amount = 0
 输出:0
示例 4:
 输入:coins = [1], amount = 1
 输出:1
示例 5:
 输入:coins = [1], amount = 2
 输出:2

经典的动态规划题目,关于动态规划的详细解读,可以参考这篇博客。假设输入coins是{1, 2, 5},金额amount是27。

f(i)表示金额为i时所需的最少金币数,则一定有如下的递推关系:f(i) = \text{min}(f(i-1)+1, f(i-2)+1), f(i-5)+1)f(i)的初始值为f(0)=0f(1)=f(2)=f(5)=1

最后的代码如下。

#include <climits>
#include <algorithm>

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int f[amount + 1];
        f[0] = 0;
        for (int i = 1; i<= amount; i++)
            f[i] = INT_MAX;
        for (int i = 1; i <= amount; i++)
            for (int j = 0; j < coins.size(); j++)
                if (coins[j] <= i && f[i - coins[j]] != INT_MAX)
                    f[i] = min(f[i], f[i - coins[j]] + 1);
        if (f[amount] == INT_MAX)
            return -1;
        return f[amount];
    }
};

五、Leetcode62:不同路径问题

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?
示例 1:


 输入:m = 3, n = 7
 输出:28
示例 2:
 输入:m = 3, n = 2
 输出:3
解释:
 从左上角开始,总共有 3 条路径可以到达右下角。
 1. 向右 -> 向下 -> 向下
 2. 向下 -> 向下 -> 向右
 3. 向下 -> 向右 -> 向下
示例 3:
 输入:m = 7, n = 3
 输出:28
示例 4:
 输入:m = 3, n = 3
 输出:6
提示:
 1. 1 <= m, n <= 100
 2. 题目数据保证答案小于等于 2 * 109

动态规划问题。假设用f(i, j)表示在第i+1行j+1列处(因为是从0开始算的)的不同路径数。

因为走到某个格子要么是从上面的格子向下走到的,要么是从左面的格子向右走到的,所以递推关系式f(i, j)=f(i-1,j)+f(i,j-1)

初始状态f(0, 0)=0f(i,0)=f(0,j)=1

代码如下。

class Solution {
public:
    int uniquePaths(int m, int n) {
        if (m == 1 || n == 1)
            return 1;

        int f[m][n];
        f[0][0] = 0;
        for (int i = 1; i < m; i++)
            f[i][0] = 1;
        for (int j = 1; j < n; j++)
            f[0][j] = 1;

        for (int i = 1; i < m; i++) 
            for (int j = 1; j < n; j++) 
                f[i][j] = f[i - 1][j] + f[i][j - 1];
        return f[m - 1][n - 1];
    }
};

六、Leetcode1:两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
 输入:nums = [2,7,11,15], target = 9
 输出:[0,1]
 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
 输入:nums = [3,2,4], target = 6
 输出:[1,2]
示例 3:
 输入:nums = [3,3], target = 6
 输出:[0,1]

第一种方法是暴力求解,使用两层循环,将数组中的每两个数都加一遍直至找到结果。这种方法时间复杂度为O(n^2)。

第二种解法使用哈希表,哈希表中存放已经遍历过的所有元素的值和位置,以值为哈希表的key、位置为value。只需要遍历一次数组,每遍历到一个元素,先查看target减去该元素得到的值是否在哈希表里,如果在就取出它的value,返回结果。否则,就将当前元素加入哈希表中。这种方法以空间换时间,时间复杂度为O(n)。

具体代码如下。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> result;
        map<int, int> my_map;
        map<int, int>::iterator iter;
        for (int i = 0; i < nums.size(); i++) {
            iter = my_map.find(target - nums[i]);
            if (iter != my_map.end()) {
                result.insert(result.end(), iter->second);
                result.insert(result.end(), i);
                return result;
            }
            my_map.insert(map<int, int>::value_type(nums[i], i));
        }
        return result;
    }
};

结果如下。


这篇文章写起来不易,如果它对你有帮助的话,麻烦给个赞吧!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353