寫在前面
華爲面試題庫刷題第一天題目整理
歡迎訪問我的個人博客網站:flamsteed
32. 最長有效括號
給定一個只包含 ‘(’ 和 ‘)’ 的字符串,找出最長的包含有效括號的子串的長度。
一共有三種時間複雜度O(N)的解法,分別是dp,棧,和計數,我們都實現一下:
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<int> dp(l,0);
for(int i=1; i<l; i++){
if(s[i]==')' && s[i-1]=='('){//情況1
dp[i] = (i-2>=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<int> a;
a.push(-1);
int maxl(0);
for(int i=0; i<l; i++){
if(s[i]=='('){
a.push(i);
}
else{
a.pop();
if(a.empty())
a.push(i);
else
if((i-a.top())>maxl) maxl = i-a.top();
}
}
return maxl;
}
};
計數法
這個方法比較tricky,只需要兩個變量left和right就能統計出答案,空間複雜度O(1)。
思路:先從左往右遍歷字符串:
- 遇到’(’,left加1
- 遇到’)’,right加1,同時進行判斷,如果此時left=right,則記錄是不是最長的長度,如果right>left,則left和right同時清零。
然後再從右往左遍歷一遍,用一樣的方法統計一遍,此時存儲的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; i<l; i++){
if(s[i]=='(')
left++;
else{
right++;
if(left==right){
if(left+right>maxl)
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;
}
};
45. 跳躍遊戲 II
給定一個非負整數數組,你最初位於數組的第一個位置。
數組中的每個元素代表你在該位置可以跳躍的最大長度。
你的目標是使用最少的跳躍次數到達數組的最後一個位置。
示例:
輸入: [2,3,1,1,4]
輸出: 2
解釋: 跳到最後一個位置的最小跳躍數是 2。從下標爲 0 跳到下標爲 1 的位置,跳 1 步,然後跳 3 步到達數組的最後一個位置。
O(N)的解法有兩種:貪心和動態規劃
貪心
每一跳都跳在下一跳最遠的位置
代碼:
class Solution {
public:
int jump(vector<int>& nums) {
if(nums.empty()) return 0;
int maxp(0),end(0),step(0);
for(int i=0; i<nums.size()-1; i++){
maxp = max(maxp,nums[i]+i);
if(i==end){
end = maxp;
step++;
}
}
return step;
}
};
dp
dp[i]記錄跳到第i位需要的最小的跳數
變量pos記錄目前跳到的位置(即dp更新到的位置)
far記錄第i位能跳到的最遠位置
此時,如果far>pos, dp[pos:far] = dp[i]+1.
代碼:
class Solution {
public:
int jump(vector<int>& nums) {
int pos = 1;
int n = nums.size();
vector<int> dp(n,0);
int i=0;
while(i<n){
int far = min(n-1,i+nums[i]);//當前這一位能跳的最遠位置,如果超出範圍則返回答案
if(pos>=n) return dp[n-1];
while(pos<=far){//更新pos~far
dp[pos] = dp[i]+1;
pos++;
}
i++;
}
return dp[n-1];
}
};
679. 24點遊戲
你有 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<int>& 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);
}
};
782. 變爲棋盤
一個 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<vector<int>>& board)
{
int n = board.size();
for(int i=0;i<n;i++)//判斷四角是否相同,不同必定不能變棋盤。
{
for(int j=0;j<n;j++)
{
if((board[0][0]^board[0][j]^board[i][0]^board[i][j])==1)
return -1;
}
}
//此時只需要判斷第一行和第一列就行了
int row=0,col=0;
int cntrow=0,cntcol=0;
for(int i=0;i<n;i++)
{
row+=board[0][i];
col+=board[i][0];
if(board[0][i]!=i%2) cntrow++; //01010... 計算錯位的個數
if(board[i][0]!=i%2) cntcol++; //01010...
}
if(row<n/2 || row>(n+1)/2) return -1;
if(col<n/2 || 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;
}
};