LeetCode程序员面试金典(第 6 版)中

目录

面试题 08.11. 硬币

面试题 08.12. 八皇后

面试题 08.13. 堆箱子

面试题 08.14. 布尔运算

面试题 10.01. 合并排序的数组

面试题 10.02. 变位词组

面试题 10.03. 搜索旋转数组

面试题 10.05. 稀疏数组搜索

面试题 10.09. 排序矩阵查找

面试题 10.10. 数字流的秩

面试题 10.11. 峰与谷

面试题 16.01. 交换数字

面试题 16.02. 单词频率

面试题 16.03. 交点

面试题 16.04. 井字游戏

面试题 16.05. 阶乘尾数

面试题 16.06. 最小差

面试题 16.07. 最大数值

面试题 16.08. 整数的英语表示

面试题 16.09. 运算

面试题 16.10. 生存人数

面试题 16.11. 跳水板

面试题 16.13. 平分正方形

面试题 16.14. 最佳直线

面试题 16.15. 珠玑妙算

面试题 16.16. 部分排序

面试题 16.17. 连续数列

面试题 16.18. 模式匹配

面试题 16.19. 水域大小

面试题 16.20. T9键盘

面试题 16.21. 交换和

面试题 16.22. 兰顿蚂蚁


面试题 08.11. 硬币

硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

题解:动态规划

这是一道升级版的青蛙跳台阶的题。注意不能将内外两个循环交换,否则和dfs一样会有重复的情况

代码:

class Solution {
public:
    int waysToChange(int n) {
        vector<int>arr{1,5,10,25};
        vector<int>dp(n+1,1);
        dp[0]=1;
        for(int k=1;k<4;++k){
            for(int i=1;i<=n;++i){     
            if (i>=arr[k])
                dp[i]=(dp[i]+dp[i-arr[k]])%1000000007;   
            }  
        }
        return dp[n];
    }
};

面试题 08.12. 八皇后

设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。

注意:本题相对原题做了扩展

题解:递归

因为题目要求,每一列,对角线和反对角线上不能有重复的‘Q'。因此,我们需要建立三个bool数组用于记录是否出现。列很简单,建立一个1*n的数组即可;对角线上的元素行和列相加是相等的;反对角线上的元素n-i+j的结果是相等的。根据上述规则来建立三个bool数组。

在递归过程中,对每一行每一列都需要遍历,满足三个数组对应的位都是false的时候,便可放Q。开始下一次的递归,值得注意的是,再下一次的循环前需要把放Q的地方变为.。

代码:

class Solution {
public:
    vector<vector<string>> solveNQueens(int n) {
        vector<bool>col(n);             //记录每一列
        vector<bool>diagonal(n+n-1);    //记录对角线
        vector<bool>back_diagonal(n*2); //记录反对角线
        vector<vector<string>>res;
        vector<string>strs(n,string(n,'.'));
        dfs(0,n,res,col,diagonal,back_diagonal,strs);
        return res;
    }
    void dfs(int i,int n,vector<vector<string>>&res,vector<bool>&col,vector<bool>&diagonal,vector<bool>&back_diagonal,vector<string>&strs){
        if(i==n){
            res.push_back(strs);
            return;
        } 
        for(int j=0;j<n;++j){
            if(col[j]||diagonal[i+j]||back_diagonal[n-i+j]) continue;
            strs[i][j]='Q';
            col[j]=diagonal[i+j]=back_diagonal[n-i+j]=true;
            dfs(i+1,n,res,col,diagonal,back_diagonal,strs);
            strs[i][j]='.';
            col[j]=diagonal[i+j]=back_diagonal[n-i+j]=false;
        }
    }
};

面试题 08.13. 堆箱子

堆箱子。给你一堆n个箱子,箱子宽 wi、深 di、高 hi。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子。实现一种方法,搭出最高的一堆箱子。箱堆的高度为每个箱子高度的总和。

输入使用数组[wi, di, hi]表示每个箱子。

题解:

代码:

面试题 08.14. 布尔运算

给定一个布尔表达式和一个期望的布尔结果 result,布尔表达式由 0 (false)、1 (true)、& (AND)、 | (OR) 和 ^ (XOR) 符号组成。实现一个函数,算出有几种可使该表达式得出 result 值的括号方法。

题解:合并之后排序

代码:

class Solution {
public:
    void merge(vector<int>& A, int m, vector<int>& B, int n) {
        for(int i=m;i<A.size();++i){
            A[i]=B[i-m];
        }    
        sort(A.begin(),A.end());
    }
};

面试题 10.01. 合并排序的数组

给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。

初始化 A 和 B 的元素数量分别为 m 和 n。

题解:

代码:

面试题 10.02. 变位词组

编写一种方法,对字符串数组进行排序,将所有变位词组合在一起。变位词是指字母相同,但排列不同的字符串。

题解:哈希+排序

遍历字符串数组,对每一个字符串进行排序,在哈希表中,对排序过的字符串进行查找。如果能找到,将原字符串添加到数组中。如果没有,重新开辟一个数组用于添加字符串。

代码:

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        vector<vector<string>>res;
        unordered_map<string,int>map;
        string temp;
        for(string i:strs){
            temp=i;
            sort(temp.begin(),temp.end());
            if(map.find(temp)!=map.end()){
                res[map[temp]].push_back(i);
            }else{
                map[temp]=res.size();
                res.push_back({i});
            }
        }
        return res;
    }
};

面试题 10.03. 搜索旋转数组

搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。

题解:二分法

数组至少一半有序,一半无序。

如果target在有序的数组里,就在里面查找。

如果target在无序的数组里,就在里面查找。

如果像 11111211这种,就把前面重复的都消掉。

代码:

class Solution {
public:
    int search(vector<int>& arr, int target) {
        int l=0,r=arr.size()-1;
        int mid=0;
        if(target==arr[0]) return 0;
        while(l<=r){
            mid=(l+r)/2;
            if(arr[mid]==target){
                while(mid>0&&arr[mid]==arr[mid-1]) --mid;
                return mid;
            }
            if(arr[mid]>arr[l]){//l~mid是递增序列
                if(target>=arr[l]&&target<arr[mid])
                    r=mid-1;
                else
                    l=mid+1;
            }
            else if(arr[mid]<arr[r]){//mid~r是递增序列
                if(target>arr[mid]&&target<=arr[r])
                    l=mid+1;
                else
                    r=mid-1;
            }
            else{//这步很关键
                while (l <= r && arr[mid] == arr[l])l++;
                while (l <= r && arr[r] == arr[mid])r--;
            }
        }
        return -1;
    }
};

面试题 10.05. 稀疏数组搜索

稀疏数组搜索。有个排好序的字符串数组,其中散布着一些空字符串,编写一种方法,找出给定字符串的位置。

题解:二分法

因为是有序排列,用普通的二分法即可,但是需要注意的一点是,如果遇到”“,那么需要一直消除直到遇到一个正常的字符串。否则二分法便会失效

代码:

class Solution {
public:
    int findString(vector<string>& words, string s) {
        int l=0,r=words.size()-1,mid=0;
        while(l<=r){
            mid=(l+r)/2;
            while(mid>l&&words[mid]=="") --mid;//把""去掉
            if(words[mid]==s)
                return mid;
            else if(s<words[mid])
                r=mid-1;
            else if(s>words[mid])
                l=mid+1;
        }
        return -1;
    }
};

面试题 10.09. 排序矩阵查找

给定M×N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。

题解:z字查找

首先,从(0,n-1)开始,也就是矩阵的右上角。

如果遇到

1.target=matrix[i][j],返回true;

2.target>matrix[i][j],i++,因为每一行有序,前面不会有更大的了;

3.target<matrix[i][j],j--,因为每一行有序,在这行中查找是否有等于target的值即可。

代码:

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.size()==0||matrix[0].size()==0) return false;
        int i=0,j=matrix[0].size()-1;
        while(i<matrix.size()&&j>=0){
            if(target==matrix[i][j])
                return true;
            else if(target>matrix[i][j]){//因为有序,所以前面的不会比它大
                ++i;
                // j=matrix[0].size()-1;
            }
            else //这一行查找即可
                --j;  
        }
        return false;
    }
};

面试题 10.10. 数字流的秩

假设你正在读取一串整数。每隔一段时间,你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。请实现数据结构和算法来支持这些操作,也就是说:

实现 track(int x) 方法,每读入一个数字都会调用该方法;

实现 getRankOfNumber(int x) 方法,返回小于或等于 x 的值的个数。

题解:

代码:

面试题 10.11. 峰与谷

在一个整数数组中,“峰”是大于或等于相邻整数的元素,相应地,“谷”是小于或等于相邻整数的元素。例如,在数组{5, 8, 4, 2, 3, 4, 6}中,{8, 6}是峰, {5, 2}是谷。现在给定一个整数数组,将该数组按峰与谷的交替顺序排序。

题解1:排序+交换

先排序,再交换奇偶位上的数即可。

代码:

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();i=i+2){
            if(i+1<nums.size()){
                swap(nums[i],nums[i+1]);
            }
        } 
    }
};

题解2:遍历+交换

遍历数组,有两种情况:

1.峰处i遇到nums[i]>nums[i-1],交换两者位置;

2.谷处i遇到nums[i]<nums[i-1],交换两者位置。

代码:

class Solution {
public:
    void wiggleSort(vector<int>& nums) {
        for(int i=1;i<nums.size();++i){
            if(i%2==0){
                if(nums[i]>nums[i-1]) swap(nums,i,i-1);
            }else{
                if(nums[i]<nums[i-1]) swap(nums,i,i-1);
            }
        }   
    }
    void swap(vector<int>& nums,int i,int j){
        nums[i]^=nums[j];
        nums[j]^=nums[i];
        nums[i]^=nums[j];
    }
};

面试题 16.01. 交换数字

编写一个函数,不用临时变量,直接交换numbers = [a, b]ab的值。

题解:按位异或

例如3(011)与5(101),两者按位异或把3变成6(110),再次异或把5变成3(011),再次异或把6变成5(101)

代码:

class Solution {
public:
    vector<int> swapNumbers(vector<int>& numbers) {
        numbers[0]^=numbers[1];
        numbers[1]^=numbers[0];
        numbers[0]^=numbers[1];
        return numbers;
    }
};

面试题 16.02. 单词频率

设计一个方法,找出任意指定单词在一本书中的出现频率。

你的实现应该支持如下操作:

WordsFrequency(book)构造函数,参数为字符串数组构成的一本书
get(word)查询指定单词在书中出现的频率

题解:哈希

这题应该是考前缀树,但是哈希更快,也更简单。

代码:

class WordsFrequency {
public:
    vector<string>books;
    unordered_map<string,int>map;
    WordsFrequency(vector<string>& book) {
        for(auto s:book){
            books.push_back(s);
            ++map[s];
        }
    }
    
    int get(string word) {
        return map[word];
    }
};

/**
 * Your WordsFrequency object will be instantiated and called as such:
 * WordsFrequency* obj = new WordsFrequency(book);
 * int param_1 = obj->get(word);
 */

面试题 16.03. 交点

给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。

要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。

题解:

代码:

面试题 16.04. 井字游戏

设计一个算法,判断玩家是否赢了井字游戏。输入是一个 N x N 的数组棋盘,由字符" ","X"和"O"组成,其中字符" "代表一个空位。

以下是井字游戏的规则:

玩家轮流将字符放入空位(" ")中。
第一个玩家总是放字符"O",且第二个玩家总是放字符"X"。
"X"和"O"只允许放置在空位中,不允许对已放有字符的位置进行填充。
当有N个相同(且非空)的字符填充任何行、列或对角线时,游戏结束,对应该字符的玩家获胜。
当所有位置非空时,也算为游戏结束。
如果游戏结束,玩家不允许再放置字符。
如果游戏存在获胜者,就返回该游戏的获胜者使用的字符("X"或"O");如果游戏以平局结束,则返回 "Draw";如果仍会有行动(游戏未结束),则返回 "Pending"。

题解:数组记录

开辟大小为n的两个数组row,col记录行和列,两个变量diagonal,anti_diagonal记录对角线和反对角线,变量pending用于记录是否有空位。
然后,开始遍历矩阵,会遇到三种情况:
1.'O',对应的row,col,diagonal,anti_diagonal做++操作;
2.'X',对应的row,col,diagonal,anti_diagonal做--操作;
3.' ',pending置为true。
在循环体内判断row,col,diagonal,anti_diagonal是否等于n或者-n,若有返回'O'或'X'。
循环结束,代表无人胜利,那么判断pending是否为true。

代码:

class Solution {
public:
    string tictactoe(vector<string>& board) {
        int n=board.size();
        vector<int>row(n,0);
        vector<int>col(n,0);
        int diagonal=0;
        int anti_diagonal=0;
        int flag=0;
        bool pending=false;
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j){
                if(board[i][j]=='O') flag=1;
                else if(board[i][j]=='X') flag=-1;
                else {
                    pending=true;//有空位
                    continue;
                }
                row[i]+=flag;
                col[j]+=flag;
                if(i==j)    diagonal+=flag;
                if(i+j==n-1)    anti_diagonal+=flag;
                if(row[i]==n||col[j]==n||diagonal==n||anti_diagonal==n)
                    return "O";
                else if(row[i]==-n||col[j]==-n||diagonal==-n||anti_diagonal==-n)
                    return "X";
            } 
        if(pending)
            return "Pending"; 
        else 
            return "Draw";
    }
};

面试题 16.05. 阶乘尾数

设计一个算法,算出 n 阶乘有多少个尾随零。

题解:数学公式

其实是一道数学题,因为阶乘里面的2的个数远大于5的个数,2*5=10。有几个5就有几个0,我们只需要知道有几个5就可以了,15有3个5,25有5个5,但是!25本身就是有两个5组成,所以25有6个5。那怎么表示呢?对n/5操作,一直到n=0为止。

代码:

class Solution {
public:
    int trailingZeroes(int n) {
        int res=0;
        while(n){
            res+=n/5;
            n/=5;
        }
        return res;
    }
};

面试题 16.06. 最小差

给定两个整数数组ab,计算具有最小差绝对值的一对数值(每个数组中取一个值),并返回该对数值的差

题解:

代码:

class Solution {
public:
    int smallestDifference(vector<int>& a, vector<int>& b) {
        sort(a.begin(),a.end());
        sort(b.begin(),b.end());
        int res=INT_MAX;
        int i=0,j=0;
        while(i<a.size()&&j<b.size()){
            long diff=a[i]-b[j];
            if(abs(diff)<res)
                res=abs(diff);
            if(diff<0){
                ++i;
            }else
                ++j;
        }
        return res;
    }
};

面试题 16.07. 最大数值

编写一个方法,找出两个数字ab中最大的那一个。不得使用if-else或其他比较运算符。

题解:

用数学公式 :

Max(a,b)=\frac{\left | a-b \right |+a+b}{2}

代码:

class Solution {
public:
    int maximum(int a, int b) {
        return (fabs((long)a-(long)b)+(long)a+(long)b)/2;
    }
};

面试题 16.08. 整数的英语表示

题解:

代码:

面试题 16.09. 运算

题解:

代码:

面试题 16.10. 生存人数

题解:

代码:


class Solution {
public:
    int maxAliveYear(vector<int>& birth, vector<int>& death) {
        vector<int>res(102,0);
        int maxval=0;
        int idx=0;
        int temp=0;
        for(int i=0;i<birth.size();++i){
            ++res[birth[i]-1900];
            --res[death[i]-1900+1];
        }
        for(int i=0;i<=100;++i){
            temp+=res[i];
            if(temp>maxval){
                maxval=temp;
                idx=i;
            }    
        }
        return idx+1900;
    }
};

面试题 16.11. 跳水板

题解:数学公式

首先,排除特殊情况,

k=0时,返回[];

shorter=longer时,返回shorter*k;

设结果F={k-i)*shorter+i*longer=k*shorter+i*(longer-shorter);

因为(longer-shorter)>0,所以结果F是随着i增大的数,所以不会重复的k+1个数。

代码:

class Solution {
public:
    vector<int> divingBoard(int shorter, int longer, int k) {
        if(k==0) return{};
        if(shorter==longer) return {shorter*k};
        vector<int>res;
        for(int i=0;i<=k;++i){
            res.push_back(k*shorter+i*(longer-shorter));
        }
        return res;
    }
};

面试题 16.13. 平分正方形

题解:

代码:

面试题 16.14. 最佳直线

题解:

代码:

面试题 16.15. 珠玑妙算

题解:

代码:

面试题 16.16. 部分排序

题解:

代码:

面试题 16.17. 连续数列

给定一个整数数组,找出总和最大的连续数列,并返回总和。

题解:动态规划

利用动态规划的思想,遍历数组x1,x2,...,xn。
当遍历到x(k)时,遇到两种情况:
1.x(k-1)的最大累加和是正数,那么加上这个值,最后x(k)的最大连续数组和是x(k)+x(k-1);
2.x(k-1)的最大累加和是非正数,那么x(k)的最大连续数组和是x(k)。
循环直至遍历完数组,最后返回最大的那个数maxval

代码:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int maxval=INT_MIN;
        int dp=0;
        for(auto n:nums){
            if(dp>0)
                dp+=n;
            else 
                dp=n;
            if(dp>maxval)
                maxval=dp;
        } 
        return maxval;  
    }
};

面试题 16.18. 模式匹配

题解:

代码:

面试题 16.19. 水域大小

题解:

代码:

面试题 16.20. T9键盘

题解:

代码:

面试题 16.21. 交换和

题解:

代码:

面试题 16.22. 兰顿蚂蚁

题解:

代码:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木白CPP

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值