1.c++比较与java,可以把main函数写在前面,自定义函数写在后面嘛?
不行,c++必须先定义函数才能进行使用
2.关于map的遍历方法
C++:
使用iterator迭代器完成遍历
#include<iostream>
#include<map>
using namespace std;
int main() {
map<int,int> mi;
map<int,int>::iterator it;
//mi.insert(1,2);
mi[2]=4;
//mi.insert(3,6);
for(it=mi.begin();it!=mi.end();it++) {
cout<<it->first<<":"<<it->second<<endl;
}
return 0;
}
这里注意注释的地方,不能直接使用insert(int,int)来添加数据。
java:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
}
3.深度学习二分查找:
基本代码,寻找key的索引值,当不存在与数组时返回-1
#include<iostream>
using namespace std;
int BiraySearch(int arr[],int key,int left,int right) {
if(left<=right) {
//要点1
int mid=left + (right-left)/2;
if(arr[mid] == key) {
return mid;
} else if (arr[mid] > key) {
//要点2
return BiraySearch(arr,key,left,mid-1);
}
return BiraySearch(arr,key,mid+1,right);
}
return -1;
}
int main() {
int a[5]={2,5,10,100,200};
int x=10;
int num=sizeof(a)/sizeof(a[0]); //要点3
cout<<BiraySearch(a,x,0,num-1)<<endl;
return 0;
}
要点1:mid的表达式也可以写成(left+right)/2,但是这样可能会引起溢出
要点2:在if判断中,我们判断的是left<=right,所以是左闭右闭去间,在发现mid不是key的索引值时,直接跳过mid搜索mid-1或者mid+1即可
在当if是left<right时,在发现mid不是key的索引值时,left的变化区间还是[mid+1,right),而right的变化区间则是[left,mid)
要点3:在c++中不像java一样,在获取数组的元素个数时直接使用length即可,我们要先取数组的sizeof值,然后再除以数组一个元素的sizeof值,即可得到个数
缺陷:在基本代码中,在我们的数组存在重复数时,当我们需要寻找目标数的最左或者最右的索引值时,我们需要怎么办呢?
寻找左侧边界的二分搜索
#include<iostream>
using namespace std;
int BiraySearch(int arr[],int key,int left,int right) {
while(left<right) {
int mid=left + (right-left)/2;
if(arr[mid]>=key) {
right=mid; //要点1
} else {
left=mid+1;
}
}
//要点2
if(left==0) return -1;
return (key==arr[left]) ? left : -1;
}
int main() {
int a[6] = {1,1,2,2,2,2};
int n=2;
int num=6; //要点3
cout<<BiraySearch(a,n,0,num)<<endl;
return 0;
}
要点1:我们要找最左侧得目标数,所以很自然是缩小right值,然后前面就说明了为啥是mid
要点2:要考虑目标数不存在与数组中得情况,当left=0或者循环完后arr[left]都不等与目标数时
要点3:在函数BiraySearch中,while循环判断是left<right,所以right值就不用减一
寻找右侧边界的二分查找
#include<iostream>
using namespace std;
int BiraySearch(int arr[],int key,int left,int right) {
//if(arr.empty()) return 0;
while(left<right) {
int mid=left + (right-left)/2;
if(arr[mid]==key) {
left=mid+1;
} else if(arr[mid] > key) {
right=mid;
} else {
left=mid+1;
}
}
if(left==0) return -1;
return (key==arr[left-1]) ? left-1 : -1; //要点1
}
int main() {
int a[6] = {1,1,2,2,2,2};
int n=2;
int num=6;
cout<<BiraySearch(a,n,0,num)<<endl;
return 0;
}
要点1:我们对left得处理是mid+1,所以可能mid==key,但是mid+1不等于,可是这时已经跳出循环了。这样得话我们在循环体外就得-1再判断是否为目标数
这里我用的是数组来进行代码编写,但是使用vector容器来进行是最好的,因为可以直接判断是否为空数组,是则直接返回即可
4.c++中的null空指针怎么表示,或者表示一个空vector,map方法
与Java不用的是,java可以使用null表示空指针,空vector,map。在c++中,我们只能使用NULL表示空指针,在表示空vector,map时,我们可以自定义创建一个无用的vector,map来进行返回
5.什么是线性时间复杂度?
时间复杂度为线性阶O(n),同理可得常数时间复杂度O(1),对数时间复杂度O(log2n),线性对数时间复杂度O(nlog2n),平方时间复杂度O(n^2),立方时间复杂度O(n^3)
6.在c++中如果要使用python中的set函数要怎么使用,头文件是什么?
c++提供unordered_set<> ,头文件为<unordered_set>
7.负数的位运算要怎么计算?
先把负数转化成unsigned类型即可计算。例如 int 类型转化成 unsigned int 型
8.记住几个关键位置的ascii值
‘0’ = 48,‘A’ = 65 , ‘a’ = 97;
9.判断是否为字母的isalpha()和判断是否为大小写的isupper()的头文件是?
ctype.h或者cctype
10.字母大小写转化的函数
tolower(char) :转化成小写 , toupper:转化成大写
11.java和c++中的string.erase的区别
java:str.erase(i , j) 从i到j,删除 j - i 个char值,即 [ i , j) 个char值
c++:str.erase(i , j) 从i 开始删除 j 个char值
12.引用 & 与复制
引用就是用另一个变量来代替该变量,当引用变量的值发生变化时,原变量也会发生变化。但是复制变量发生值得改变也不会影响原变量
13.引用作为函数参数的特点
- 被调函数中对形参变量的操作就是对其相应目标对象(在主调函数中)的操作
- 在内存中并没有产生实参的副本,直接在实参上进行操作,传递参数的效率更高,所占内存也更少
- 在被调函数中同样要给形参分配内存单元。在主调函数的调用点处,必须用变量的地址作为实参,所以引用更加容易使用,更清晰
14.深度优先与广度优先搜索的深度学习:一下分析都是以树为例子
原理:
深度优先搜索(Depth First Search, 简称 DFS):从根节点到叶节点,当到某一叶节点时,就返回上一步,搜索有无其他叶子路径。直到全部的叶节点都遍历完
广度优先搜索(Breadth First Search,简称 BFS):从左到右对每一层的树节点进行遍历,直到全部遍历完
代码实现:
DFS:
因为DFS的搜索方式是从上往下的,所以有两种方法:
1.递归法:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
void DFS(TreeNode *root) {
if(root == NULL) return ;
cout<<root-<val<<endl;
DFS(root->left);
DFS(root->right);
}
上面的递归法使用的是前序遍历方式,中后序方法一样。
2.存栈法:
public static void DFSWithStack(TreeNode root) {
if (root == null) {
return;
}
stack<Node> stack = new Stack<>();
// 先把根节点压栈
stack.push(root);
while (!stack.isEmpty()) {
TreeNode treeNode = stack.top();
stack.pop();
// 遍历节点
process(treeNode)
// 先压右节点
if (treeNode->right != null) {
stack.push(treeNode.right);
}
// 再压左节点
if (treeNode->left != null) {
stack.push(treeNode.left);
}
}
}
思路如下:
- 对于每个节点来说,先遍历当前节点,然后把右节点压栈,再压左节点(这样弹栈的时候会先拿到左节点遍历,符合深度优先遍历要求)
- 弹栈,拿到栈顶的节点,如果节点不为空,重复步骤 1, 如果为空,结束遍历。
BFS:
因为BFS是从左到右遍历的,所以递归法并不适用。可以使用队列来完成操作:
/**
* 使用队列实现 bfs
* @param root
*/
void BFS(TreeNode root) {
if (root == null) {
return;
}
queue<TreeNode> q;
q.push(root);
while (!q.isEmpty()) {
TreeNode node = q.front();
q.pop();
System.out.println("value = " + node.value);
TreeNode left = node->left;
if (left != null) {
q.push(left);
}
TreeNode right = node->right;
if (right != null) {
q.push(right);
}
}
}
15.deque的用法?
双指针的queue用法,可以在头部插入,也可以在尾部插入
16.stoi和to_string的头文件
都是#include<string>
17.拓扑排序
概念:
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边∈E(G),则u在线性序列中出现在v之前。
算法流程
- 想遍历节点,把节点入度为0得节点分离出来,然后把这些节点得邻接节点入度减一
- 重复步骤1,直到全部节点都分离出来
- 检查是否还存在入度不为0得节点,若没有则说明没有环
练习题:
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> res(numCourses , vector<int>());
vector<int> innum(numCourses);
for(int i = 0; i < prerequisites.size(); i++) {
innum[prerequisites[i][0]]++;
res[prerequisites[i][1]].push_back(prerequisites[i][0]);
}
queue<int> q;
for(int i = 0; i < numCourses; i++) {
if(innum[i] == 0) {
q.push(i);
}
}
int cnt = 0;
while(!q.empty()) {
int tmp = q.front();
q.pop();
cnt++;
for(int i = 0; i < res[tmp].size(); i++) {
innum[res[tmp][i]]--;
if(innum[res[tmp][i]] == 0) q.push(res[tmp][i]);
}
}
return cnt == numCourses;
}
};
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> graph(numCourses , vector<int>());
vector<int> indegrees(numCourses , 0) , res;
for(int i = 0; i < prerequisites.size(); i++) {
indegrees[prerequisites[i][0]]++;
graph[prerequisites[i][1]].push_back(prerequisites[i][0]);
}
//定义优先队列
priority_queue<int, vector<int>, greater<int>> q;
for(int i = 0; i < numCourses; i++) {
if(indegrees[i] == 0) {
q.push(i);
}
}
while(!q.empty() && res.size() < numCourses) {
int temp = q.top();
q.pop();
res.push_back(temp);
for(int i = 0; i < graph[temp].size(); i++) {
indegrees[graph[temp][i]]--;
if(indegrees[graph[temp][i]] == 0) q.push(graph[temp][i]);
}
}
if(res.size() == numCourses) {
return res;
} else return {};
}
};