1. 二维数组的查找
二维数组中的查找_牛客题霸_牛客网 (nowcoder.com)
法一:
从右上往左下找,由于每一行每一列都是递增的,
- 当前位置小于target, target在下一行,h++。
- 当前位置大于target, target在这一行,w—。
- 相等,表示找到了返回true。
class Solution {
public:
bool Find(int target, vector<vector<int> >& array) {
if(array.size() == 0 && array[0].size()) return false;
int row = array.size(), col = array[0].size();
int h = 0, w = col - 1;
while(w >= 0 && h < row){
if(array[h][w] > target) w--;
else if(array[h][w] < target) h++;
else return true;
}
return false;
}
};
法二:
不考虑每一列的顺序,只利用每一行的有序性,在每一行中都使用二分法。
class Solution {
public:
bool hasFound(vector<int> & array,int target){
int start = 0,end = array.size() - 1;
while(start <= end){
int mid = start + (end - start) / 2;
if(array[mid] < target) start = mid + 1;
else if(array[mid] > target) end = mid - 1;
else return true;
}
return false;
}
bool Find(int target, vector<vector<int> >& array) {
if(array.size() == 0 || array[0].size() == 0) return false;
for(int i = 0;i<array.size();i++){
if(hasFound(array[i],target)) return true;
}
return false;
}
};
2. 替换空格
记得当时在Leetcode上做的时候参数是string,牛客是str,不过都一样。
法一:
若参数是string的话还得resize一下,str的话可以直接写,但这样其实本身并不优雅。
class Solution {
public:
void replaceSpace(char *str,int length) {
int cnt = 0;
for(int i = 0;i<length;i++){
if(str[i] == ' ') cnt++;
}
int totalLength = length + 2* cnt;
str[totalLength] = '\0';
for(int i = length,j = totalLength;i>=0 && i != j;i--){
if(str[i] != ' ') str[j--] = str[i];
else{
str[j--] = '0';
str[j--] = '2';
str[j--] = '%';
}
}
}
};
其他
如果参数是string的话就方法就更多了。
- 正则
- replace等
3. 从尾到头打印链表
从尾到头打印链表_牛客题霸_牛客网 (nowcoder.com)
法1:
从前往后保存,然后reverse一下就行了。
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
ListNode* cur = head;
vector<int> ans;
while(cur){
ans.push_back(cur->val);
cur = cur->next;
}
reverse(ans.begin(),ans.end());
return ans;
}
};
法2:
递归
class Solution {
public:
void recursion(ListNode* head,vector<int>& ans){
if(head != nullptr){
recursion(head->next, ans);
ans.push_back(head->val);
}
}
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> ans;
recursion(head,ans);
return ans;
}
};
法3:
还可以先弄到栈里,然后一个个出栈。但感觉跟法1的reverse区分度不大。代码略。
4. 重建二叉树
法一:
根据二叉树先序遍历和中序遍历的规则,找到根节点,递归建立二叉树。
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int>& preOrder, vector<int>& vinOrder) {
// write code here
if(preOrder.size() == 0 || vinOrder.size() == 0) return nullptr;
int mid = distance(begin(vinOrder),find(vinOrder.begin(),vinOrder.end(),preOrder[0]) );
TreeNode* root = new TreeNode(preOrder[0]);
vector<int> leftPre(preOrder.begin() + 1,preOrder.begin() + mid + 1);
vector<int> rightPre(preOrder.begin() + mid + 1,preOrder.end());
vector<int> leftVin(vinOrder.begin(),vinOrder.begin() + mid);
vector<int> rightVin(vinOrder.begin() + mid + 1,vinOrder.end());
root->left = reConstructBinaryTree(leftPre, leftVin);
root->right = reConstructBinaryTree(rightPre, rightVin);
return root;
}
};
法二:
空间换时间。每次都用distance去中序序列中找根节点太麻烦了,直接一开始用哈希表记录每个节点和它的索引。之后就不需要每次计算距离了,只要去查哈希表即可。
class Solution {
public:
TreeNode* reConCore(vector<int>& preOrder,unordered_map<int,int>& mp,int root,int start,int end){
if(start > end) return nullptr;
TreeNode* tree = new TreeNode(preOrder[root]);
int vinIndex = mp[preOrder[root]];
tree->left = reConCore(preOrder, mp, root + 1, start, vinIndex - 1);
tree->right = reConCore(preOrder, mp, (root + 1) + (vinIndex - start ), vinIndex + 1 , end );
return tree;
}
TreeNode* reConstructBinaryTree(vector<int>& preOrder, vector<int>& vinOrder) {
// write code here
unordered_map<int,int> mp;
for(int i = 0;i<vinOrder.size();i++) mp.insert({vinOrder[i],i});
return reConCore(preOrder,mp,0,0,preOrder.size() - 1);
}
};
5. 用两个栈来实现队列
用两个栈实现队列_牛客题霸_牛客网 (nowcoder.com)
很简单,一个栈进,一个栈出。pop时如果出栈为空就把入栈的队列里的数据放放进出栈。
class Solution {
public:
void push(int node) {
stack1.push(node);
}
int pop() {
int temp;
if (stack2.empty()) {
while (!stack1.empty()) {
temp = stack1.top();
stack1.pop();
stack2.push(temp);
}
}
temp = stack2.top();
stack2.pop();
return temp;
}
private:
stack<int> stack1;
stack<int> stack2;
};
6. 旋转数组的最小数字
旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com)
法一:
常规做法,直接遍历找第一个减小的数字。(也可以sort后,直接return nums[0])
class Solution {
public:
int minNumberInRotateArray(vector<int>& nums) {
for(int i = 1;i<nums.size();i++){
if(nums[i] < nums[i-1]) return nums[i];
}
return nums[0];
}
};
法二:
使用二分法。虽然数组不是完全有序,但
- 每次
nums[mid] < nums[right]
时,表示右边有序。 - 两者相等时,可能有两种情况或者是右边全是一个数,或者是最小值在右边(数值先小后大,故两者相等)。
- 每次
nums[mid] > nums[right]
时,表示最小值在右边。 - 边界控制,由于最后left和right会控制相邻的两个数值中。故边界为
left + 1 < right
。否则会陷入死循环。
class Solution {
public:
int minNumberInRotateArray(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while(left + 1 < right){
int mid = left + (right - left) / 2;
if(nums[mid] < nums[right]) right = mid;
else if(nums[mid] == nums[right]) right--;
else left = mid;
}
return min(nums[left],nums[right]);
}
};
7. 斐波那契数列
斐波那契数列_牛客题霸_牛客网 (nowcoder.com)
经典题目
class Solution {
public:
int Fibonacci(int n) {
if(n <= 2) return 1;
else return Fibonacci(n-1) + Fibonacci(n-2);
}
};
8. 跳台阶
经典题目。
class Solution {
public:
int jumpFloor(int number) {
if(number <= 2) return number;
else return jumpFloor(number - 1) + jumpFloor(number - 2);
}
};
9. 跳台阶扩展问题
跳台阶扩展问题_牛客题霸_牛客网 (nowcoder.com)
法一:
经典dp
class Solution {
public:
int jumpFloorII(int number) {
vector<int> dp(number + 1);
dp[0] = 1;
dp[1] = 1;
for(int i = 2;i< dp.size();i++){
dp[i] = 2* dp[i-1];
}
return dp[number];
}
};
法二:
发现规律,2^(n-1)
;
class Solution {
public:
int jumpFloorII(int number) {
if(number <= 1) return 1;
else return pow(2,number - 1);
}
};
10. 矩阵覆盖
本质还是斐波那契。
class Solution {
public:
int rectCover(int number) {
if(number <=2 ) return number;
else return rectCover(number - 1) + rectCover(number - 2);
}
};