目录
【前言】洛谷闯关暂时告一段落,之后会把笔记放上来。这几天参加一个打卡活动,用的LeetCode和AcWing 。一天5题,打卡二十一天。 如果有想要一起小伙伴在下方留言吧~
1 数组中重复的数字
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
笔记
- 时间复杂度 o(n),额外空间复杂度 o(1)
- 在解看似简单的题目时,要考虑更优化的方案。解题思路:因题目说明,所有数字取值范围 0—n-1,所以我们依次把与下标相等的数放在当前下标的位置,若当前位置已经被占用,说明重复了
初始数组 :
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
值 | 2 | 3 | 1 | 0 | 2 | 5 | 3 |
依次交换:(遍历到第二个 2 时发现冲突)
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
值 | 0 | 1 | 2 | 3 | 2 | 5 | 3 |
- 若用 哈希, 与此解时间复杂度一样,额外空间复杂度o(n)
代码
class Solution {
public:
bool duplicate(int numbers[], int length, int* duplication) {
//以上是题目给定模板
for(int i=0;i<length;i++) if(numbers[i]<0||numbers[i]>length-1) return false; //筛选不符合条件的
for(int i=0;i<length;i++){
while(i != numbers[i]&& numbers[numbers[i]] != numbers[i])
swap(numbers[i],numbers[numbers[i]]);
if(i != numbers[i] && numbers[i]==numbers[numbers[i]]) {
*duplication=numbers[i];
return true ;
}
}
return false;
}
};
2 不修改数组找出重复的数字
题目描述
与上题题目一样。
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
笔记
- 用 二分思想
/*
二分模板一共有两个,分别适用于不同情况。
算法思路:假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。
版本1
当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。
*/
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
/*版本2
当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。
*/
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
/*作者:yxc
链接:https://www.acwing.com/blog/content/31/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*/
for (auto x : nums)
:迭代容器中所有的元素,x为每个元素的临时名称
等同于:for (vector<int>::iterator iter = nums.begin(); iter != nums.end(); iter++)
代码
class Solution {
public:
int duplicate(vector<int>& numbers) {
int l=1,r=numbers.size()-1;
while(l<r){
int mid=l+r >> 1; //[0,mid]和[mid+1,r]两部分
int s=0;
for(auto x:numbers) s += x>=l && x<=mid;
if(s > mid-l+1) r=mid;
else l=mid+1;
}
return r;
}
};
3 二维数组中的查找
题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
样例
输入数组:
[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]
如果输入查找数值为7,则返回true,
如果输入查找数值为5,则返回false。
笔记
- vector 二维数组获取长度:
int i = a.size()-1; // 行数
int j = a[0].size()-1; // 列数
- 算法思想:由题可知,二维数组每行从左到右递增,每列从上到下递减,类似于二分思想,找到一个中间数 mid,即右上角的数,当 target > mid 时,直接找下一行;当 target < mid 时,直接找前一列。这样可剪枝,每次都会省去查找一列或一行,最总减小算法复杂度
代码
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
if(array.empty()||array[0].empty()) return false;
int i=0,j=array[0].size()-1,n=array.size();
while(i<n && j>=0){
// 1 出口
if(array[i][j]==target) return true;
if(array[i][j]<target) i++;
else j--;
}
return false;
}
};
4 从尾到头打印链表
题目描述
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
笔记
- 水题。这道题主要是学会了当题目给出指针时如何利用指针得到数组
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int> res,ArrayList;
while(head){
res.push_back(head->val);
head = head->next;
}
for(int i=res.size()-1;i>=0;i--){
int temp=res[i];
ArrayList.push_back(temp);
}
return ArrayList;
}
};
5 重建二叉树
题目描述
输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。
注意:
二叉树中每个节点的值都互不相同;
输入的前序遍历和中序遍历一定合法;
样例
给定:
前序遍历:[3, 9, 20, 15, 7]
中序遍历:[9, 3, 15, 20, 7]
返回:[3, 9, 20, null, null, 15, 7, null, null, null, null]
返回的二叉树如下所示:
3
/
9 20
/
15 7
笔记
- 复习了建立二叉树。
- 算法思想:无论是前序+中序建树 还是后序+中序建树,都以中序下标为轴划分左右子树,所以将中序下标保存,以便之后确定结点的下标位置。
- c++中,null 为整数0;nullptr 为 空指针
- C++11 中引入的auto主要有两种用途:自动类型推断和返回值占位。
TreeNode* left = dfs(pl+1,pl+k-il,il,k-1);
可替换为auto left = dfs(pl+1,pl+k-il,il,k-1);
- 数组可直接porder = pre; inorder = vin;
class Solution {
public:
map<int,int> hash; //为快速找出 中序遍历中某个数的位置
vector<int> porder,inorder; //为了方便
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
porder = pre; inorder = vin;
for(int i=0;i<inorder.size();i++) hash[inorder[i]]=i;
return dfs(0,porder.size()-1,0,inorder.size()-1);
}
TreeNode* dfs(int pl,int pr,int il,int ir){
if(pl>pr) return nullptr; //返回null
TreeNode*root = new TreeNode(porder[pl]);
int k = hash[root->val];
TreeNode* left = dfs(pl+1,pl+k-il,il,k-1);
TreeNode* right = dfs(pl+k-il+1,pr,k+1,ir);
root->left = left,root->right=right;
return root;
}
};
6 二叉树的下一个节点
题目描述
给定一棵二叉树的其中一个节点,请找出中序遍历序列的下一个节点。
注意:
如果给定的节点是中序遍历序列的最后一个,则返回空节点;
二叉树一定不为空,且给定的节点一定不是空节点;
样例
假定二叉树是:[2, 1, 3, null, null, null, null], 给出的是值等于2的节点。
则应返回值等于3的节点。
解释:该二叉树的结构如下,2的后继节点是3。
给定一棵二叉树的其中一个节点,请找出中序遍历序列的下一个节点。
注意:
如果给定的节点是中序遍历序列的最后一个,则返回空节点;
二叉树一定不为空,且给定的节点一定不是空节点;
样例
假定二叉树是:[2, 1, 3, null, null, null, null], 给出的是值等于2的节点。
则应返回值等于3的节点。
解释:该二叉树的结构如下,2的后继节点是3。
2
/
1 3
代码
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
pNodeublic:
TreeLinkNode* GetNext(TreeLinkNode* pNodeNode)
{
// 1 有右孩子:右孩子
if(pNode->right){
pNode=pNode->right;
while(pNode->left) pNode=pNode->left;
return pNode;
}
// 2 无右孩子:while(pop()),top()为其父亲的左孩子 —— 下一个结点父亲;top()为其父亲的右孩子,继续出栈
while(pNode->next&&pNode==pNode->next->right) pNode=pNode->next;
return pNode->next;
}
};
7 用两个栈实现队列
题目描述
请用栈实现一个队列,支持如下四种操作:
push(x) – 将元素x插到队尾;
pop() – 将队首的元素弹出,并返回该元素;
peek() – 返回队首元素;
empty() – 返回队列是否为空;
注意:
你只能使用栈的标准操作:push to top,peek/pop from top, size 和 is empty;
如果你选择的编程语言没有栈的标准库,你可以使用list或者deque等模拟栈的操作;
输入数据保证合法,例如,在队列为空时,不会进行pop或者peek等操作;
样例
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // returns 1
queue.pop(); // returns 1
queue.empty(); // returns false
笔记
- stack 可用 size() 函数
代码
class MyQueue {
public:
/** Initialize your data structure here. */
stack<int> s,cache;
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
s.push(x);
}
void copy(stack<int> &a,stack<int> &b){
while(!a.size()){
b.push(a.top());
a.pop();
}
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
int temp;
copy(s,cacae);
int ans=cache.top(); cache.pop();
copy(cache,s);
return ans;
}
/** Get the front element. */
int peek() {
int temp;
copy(s,cacae);
int ans=cache.top();
copy(cache,s);
return ans;
}
/** Returns whether the queue is empty. */
bool empty() {
return s.empty();
}
};
/**
1. Your MyQueue object will be instantiated and called as such:
2. MyQueue obj = MyQueue();
3. obj.push(x);
4. int param_2 = obj.pop();
5. int param_3 = obj.peek();
6. bool param_4 = obj.empty();
*/
8 斐波那契数列
题目描述
f [n] = f [n-1] + f [n-2]
输入一个整数 n ,求斐波那契数列的第 n 项。
假定从0开始,第0项为0。(n<=39)
笔记
- 斐波那契的扩展,分享 :求解 斐波那契 的若干方法 https://www.acwing.com/blog/content/25/
代码
class Solution {
public:
int Fibonacci(int n) {
int a=0,b=1,c;
while(n--){
c=a+b;
a=b;
b=c;
}
return a;
}
};