华为面试题库刷题第一天题目整理
欢迎访问我的个人博客网站:flamsteed
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
一共有三种时间复杂度O(N)的解法,分别是dp,栈,和计数,我们都实现一下:
dp思路:dp一位数组存放到目前这一位字符的有效子串长度,所以所有’(‘对应的位置都是0,而’)'分两种情况:
s[i]=’)’ 且 s[i-1]=’(’,则
dp[i] = dp[i-2] + 2;
s[i]=’)’ 且 s[i-1]=’)’,此时若s[i-dp[i-1]-1]=’(’,则
dp[i] = dp[i-1] + dp[i-dp[i-1]-2] + 2;
只有这两种情况会出现有效的括号子串,遍历一遍之后统计最大长度即可。
代码:
class Solution {
public:
int longestValidParentheses(string s) {
if(s.empty()||s.length()==1) return 0;
int l = s.length();
vector dp(l,0);
for(int i=1; i=0 ? dp[i-2] : 0 ) +2;//边界情况需要考虑,不能越界
}
else if(s[i]==')'&&s[i-1]==')'){//情况2
if(i-dp[i-1]>=1 && s[i-dp[i-1]-1]=='(')
dp[i] = dp[i-1] + (i-dp[i-1]>=2 ? dp[i-dp[i-1]-2]:0) + 2;//同上
}
}
int ans = 0;
for(auto i : dp)
if(i>ans) ans = i;
return ans;
}
};
括号匹配的题目用栈这个数据结构其实是最合适的,先将-1存放进栈顶。
代码:
class Solution {
public:
int longestValidParentheses(string s) {
if(s.empty()||s.length()==1) return 0;
int l = s.length();
stack a;
a.push(-1);
int maxl(0);
for(int i=0; imaxl) maxl = i-a.top();
}
}
return maxl;
}
};
这个方法比较tricky,只需要两个变量left和right就能统计出答案,空间复杂度O(1)。
思路:先从左往右遍历字符串:
然后再从右往左遍历一遍,用一样的方法统计一遍,此时存储的maxlength就是答案。
代码:
class Solution {
public:
int longestValidParentheses(string s) {
if(s.empty()||s.length()==1) return 0;
int l = s.length();
int left(0), right(0),maxl(0);
for(int i=0; imaxl)
maxl = left+right;
}
else if(right>left){
left = 0;
right = 0;
}
}
}
left = 0;
right = 0;
for(int i=l-1; i>=0; i--){
if(s[i]==')')
right++;
else{
left++;
if(left==right){
if(left+right>maxl)
maxl = left+right;
}
else if(left>right){
left = 0;
right = 0;
}
}
}
return maxl;
}
};
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
示例:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
O(N)的解法有两种:贪心和动态规划
每一跳都跳在下一跳最远的位置
代码:
class Solution {
public:
int jump(vector& nums) {
if(nums.empty()) return 0;
int maxp(0),end(0),step(0);
for(int i=0; i
dp[i]记录跳到第i位需要的最小的跳数
变量pos记录目前跳到的位置(即dp更新到的位置)
far记录第i位能跳到的最远位置
此时,如果far>pos, dp[pos:far] = dp[i]+1.
代码:
class Solution {
public:
int jump(vector& nums) {
int pos = 1;
int n = nums.size();
vector dp(n,0);
int i=0;
while(i=n) return dp[n-1];
while(pos<=far){//更新pos~far
dp[pos] = dp[i]+1;
pos++;
}
i++;
}
return dp[n-1];
}
};
你有 4 张写有 1 到 9 数字的牌。你需要判断是否能通过 *,/,+,-,(,) 的运算得到 24。
示例 1:
输入: [4, 1, 8, 7]
输出: True
解释: (8-4) * (7-1) = 24
解法:四个数字,三个符号位,126244*4=9216种可能的情况,暴搜就完事了,O(1)时间复杂度,用递归就行了,一个运算符一层递归。
代码:
class Solution {
public:
bool judgePoint24(vector& nums) {
double a,b,c,d;
a = nums[0];
b = nums[1];
c = nums[2];
d = nums[3];
return judgePoint24_4(a,b,c,d);
}
bool judgePoint24_1(double a){
return abs(a-24)<1e-6;
}
bool judgePoint24_2(double a, double b){
return
judgePoint24_1(a+b)||
judgePoint24_1(a-b)||
judgePoint24_1(a*b)||
judgePoint24_1(a/b)||
judgePoint24_1(b-a)||
judgePoint24_1(b/a);
}
bool judgePoint24_3(double a, double b, double c){
return
judgePoint24_2(a+b,c)||
judgePoint24_2(a-b,c)||
judgePoint24_2(a*b,c)||
judgePoint24_2(a/b,c)||
judgePoint24_2(b-a,c)||
judgePoint24_2(b/a,c)||
judgePoint24_2(a+c,b)||
judgePoint24_2(a-c,b)||
judgePoint24_2(a*c,b)||
judgePoint24_2(a/c,b)||
judgePoint24_2(c-a,b)||
judgePoint24_2(c/a,b)||
judgePoint24_2(b+c,a)||
judgePoint24_2(b-c,a)||
judgePoint24_2(b*c,a)||
judgePoint24_2(b/c,a)||
judgePoint24_2(c-b,a)||
judgePoint24_2(c/b,a);
}
bool judgePoint24_4(double a, double b, double c, double d){
return
judgePoint24_3(a+b,c,d)||
judgePoint24_3(a-b,c,d)||
judgePoint24_3(a*b,c,d)||
judgePoint24_3(a/b,c,d)||
judgePoint24_3(b-a,c,d)||
judgePoint24_3(b/a,c,d)||
judgePoint24_3(a+c,b,d)||
judgePoint24_3(a-c,b,d)||
judgePoint24_3(a*c,b,d)||
judgePoint24_3(a/c,b,d)||
judgePoint24_3(c-a,b,d)||
judgePoint24_3(c/a,b,d)||
judgePoint24_3(a+d,b,c)||
judgePoint24_3(a-d,b,c)||
judgePoint24_3(a*d,b,c)||
judgePoint24_3(a/d,b,c)||
judgePoint24_3(d-a,b,c)||
judgePoint24_3(d/a,b,c)||
judgePoint24_3(b+c,a,d)||
judgePoint24_3(b-c,a,d)||
judgePoint24_3(b*c,a,d)||
judgePoint24_3(b/c,a,d)||
judgePoint24_3(c-b,a,d)||
judgePoint24_3(c/b,a,d)||
judgePoint24_3(b+d,a,c)||
judgePoint24_3(b-d,a,c)||
judgePoint24_3(b*d,a,c)||
judgePoint24_3(b/d,a,c)||
judgePoint24_3(d-b,a,c)||
judgePoint24_3(d/b,a,c)||
judgePoint24_3(c+d,a,b)||
judgePoint24_3(c-d,a,b)||
judgePoint24_3(c*d,a,b)||
judgePoint24_3(c/d,a,b)||
judgePoint24_3(d-c,a,b)||
judgePoint24_3(d/c,a,b);
}
};
一个 N x N的 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置。
输出将这个矩阵变为 “棋盘” 所需的最小移动次数。“棋盘” 是指任意一格的上下左右四个方向的值均与本身不同的矩阵。如果不存在可行的变换,输出 -1。
示例:
输入: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]
输出: 2
解释:
一种可行的变换方式如下,从左到右:
0110 1010 1010
0110 --> 1010 --> 0101
1001 0101 1010
1001 0101 0101
第一次移动交换了第一列和第二列。
第二次移动交换了第二行和第三行。
解法:题目看起来复杂,其实只要分析清楚了就很简单,行列是正交的,所以可以分开计算代价,且方法一样。
判断方法很多,我这里用了代码较少的一种:任意矩形的四个角的格子必须都是1或者都是0,否则一定不能变成棋盘,因为四个角的关系通过换行和换列无法改变。
判断完之后就计算就行了,行和列只会有两种数列,而且是01互换的,所以只需要计算第一行和第一列的代价就行了。
计算方法:统计位置不对的格子数,然后算较小的一个(需要判断一下边长的奇偶情况,详见代码注释)。
代码:
class Solution {
public:
int movesToChessboard(vector>& board)
{
int n = board.size();
for(int i=0;i(n+1)/2) return -1;
if(col(n+1)/2) return -1;//判断1的个数是否符合要求
int res=0;
if(n%2==0)
{//偶数格两种方法需要比较出较小的
res+=min(cntrow,n-cntrow);
res+=min(cntcol,n-cntcol);
}
else
{//奇数格的话只有一种排法,因为只能变偶数格。
if(cntrow%2==1)
cntrow = n-cntrow;
if(cntcol%2==1)
cntcol = n-cntcol;
res=cntrow+cntcol;
}
return res/2;
}
};