考研初试代码衍生题目+考研复试上机算法学习

C++头文件

//c++头文件
#include<iostream>
#include <algorithm> 
using namespace std;

Vector类型

//头文件
#include <vector>

//vector类型
vector<int> v1;
vector<vector<int> > v2;            //注意空格,相当于二维数组int a[n][n];
vector<int> v3 = {1,2,3,4,5};       //列表初始化,注意使用的是花括号   
vector<int> v5(5,-1);               //初始化为-1,-1,-1,-1,-1,数目+初始化的值 
vector<int> v7(10);                 //默认初始化为10个0,先开辟固定空间,很重要!!!
vector<vector<int>> v8(3,vector<int>(3,0));  //定义v8[3][3]初始化

//vector的各种操作
v5.front();                        //访问第一个元素
v5.back();                         //访问最后一个元素
v5.pop_back();                     //删除最后一个元素
v5.push_back(6);                   //加入一个元素并把它放在最后
v5.clear();                        //清除所有内容
v5.empty();                        //判断vector是否为空
v5.size();                         //给出vector的大小
v5.insert(v5.begin()+1,9);         //在第二个位置插入新元素9
v5.erase(v5.begin()+3);            //删除第四个元素

Stack类型

//头文件
#include<stack>

//stack类型
整型(int)						stack<int> s
浮点型(floatdouble)			stack<float> q    stack<double> s
字符型(char)					stack<char> s
字符串型(string)				stack<string> s
指针类型(ListNode*)	        stack<ListNode*> s
二元结构体类型(pair)             stack<pair<int,int>> s

//相关栈的操作
s.empty();     如果栈为空返回true,否则返回false
s.size();      返回栈中元素的个数
s.pop();       删除栈顶元素
s.top();       返回栈顶的元素,但不删除
s.top()=a;     修改栈顶元素
s.push(val);   在栈顶压入新元素val

Queue类型

//头文件
#include <queue>

//queue类型
queue<int> q;
queue<ListNode*> q;

//queue的各种操作
q.push();   //从队尾入队
q.pop();    //从队头出队
q.front();  //返回队头元素
q.back();   //返回队尾元素
q.size();   //返回队长度
q.empty();  //判断是否队空

Set类型

//头文件
#include <set>

//定义set类型
set<int> s1 = {9,8,,5,6,7,7 };   //自动排序,从小到大,剔除相同项
set<string> s2 = { "hello" };    //字典序排序
unordered_set<int> s3;   		 //不会排序的,但是会剔除相同项

//set的相关函数使用
s1.insert(9);       //有这个值了,do nothing
s2.insert("aaa");   //没有这个字符串,添加并且排序
s1.find(9);         //寻找元素:不存在会返回s1.end(),个人觉得很难用!!
s1.count(9);        //看元素存在不存在会返回1/0,个人觉得好用!!!

//set的适用场景
set缺点:必须使用迭代器遍历 无法随机存取
set优点:如果题目要求元素唯一可以用set

String类型

//头文件
#include <string>

//string类型
string s1;             //初始化字符串,空字符串
string s3 = "I am";    //直接初始化,s3存了字符串
string s4(10, 'a');    //s4存的字符串是aaaaaaaaaa

//string的各种操作
string s8 = s3 + s4;        //将两个字符串合并成一个
s8.size();                  //字符串的大小
s8.empty();			        //判断字符串为空返回true,否则返回false
cout<<stoi(ss);             //字符串转int
if(s[i]>='a'&&s[i]<='z')    //判断是否为小写字母
if(s[i]>='A'&&s[i]<='Z')    //判断是否为大写字母
if(s[i]>='0'&&s[i]<='9')    //判断是否为数字
s[0]-'0';                   //如果为数字字符可以通过此法获取数字
s8.push_back('a');          //string也可以push_back
string str=s.substr(开始,长度); //获取子串

堆元素类型

//头文件
#include<algorithm.h>

//堆元素操作
vector<int> v1={10,30,22,6,15,9};                  //建立在vector的基础上
make_heap(v1.begin(), v1.end());                   //默认创建大顶堆(从小到大)
make_heap(v1.begin(), v1.end(), greater<int>());   //创建小顶堆(从大到小)

v1.push_back(4);
push_heap(v1.begin(), v1.end());                   //push_heap插入数据恢复成堆
push_heap(v1.begin(), v1.end(), greater<int>());   

pop_heap(v1.begin(), v1.end());                    //pop_heap堆顶元素放到末尾
pop_heap(v1.begin(), v1.end(), greater<int>());
v1.pop_back();                                     //删除堆顶元素

sort_heap(v1.begin(), v1.end());                   //大顶堆进行从小到大堆排序
sort_heap(v1.begin(), v1.end(), greater<int>());   //小顶堆进行从大到小堆排序

Map类型

//头文件
#include <map>

//map数据的访问
map<string,int> m;            //默认有序map,参数key+value(key是唯一的)
unordered_map<int,int> m1;    //无序map,不会自动排序
m["Kobe"] = 100;              //给key赋予value

//map的相关函数
m.size();              //返回map中元素的个数
m.erase("Kobe");       //通过关键字来删除键值对
m.clear();             //清空map全部键值对
m.count(k);            //返回键K用于查看存不存在1/0,非访问value操作
m.find(9);             //寻找元素:不存在会返回m.end(),个人觉得很难用!!
if(m1 == m2)           //两个map之间可以之间比较
m.insert(pair<string,int>("Mary",89));  //通过insert函数来实现增加元素
m["不存在的键"]++;      //会自动添加不存在的键,并且值初始化为0,再加加变为1

//map的遍历操作
for(map<int, int>::iterator it = m.begin();it!=m.end();it++){
	cout << it->first << "  " << it->second << endl;
}

Pair类型

//头文件
#include<utility>

//pair类型(二元结构体)
带初始值的     pair<string, int> p={"wangyaqi",1};
不带初始值的   pair<string, int> p;
结构体数组     pair<int,int> p[20];

//访问数据
p[i].first              代表第一个元素
p[i].secondsecond       代表第二个元素
st.push({1,1});         往栈压pair类型

输入输出操作

//读取一行字符串
string str;
cin>>str;              //遇到空格或者回车键即停止
getline(cin, str);     //获取一整行包括空格遇到回车停止
//输入包含多组测试数据,每组数据占一行,多少组未知
string s;
while(cin>>s){
	//处理s的操作	
}

常用STL自带算法

//排序算法
sort(v1.begin(), v1.end());                     //从小到大排序
sort(v1.begin(), v1.end(), greater<int>());     //从大到小排序

动态规划绝妙入门讲解

 动态规划的三个解题步骤是:1)定义子问题f(n): 规模缩小 原问题要能由子问题表示 确定dp数组以及下标的含义
(2)写出子问题的递推关系: 重点思考和f(n-1)f(n-2)的递推关系 dp数组如何初始化
(3)确定DP计算顺序: 最好使用自底向上的DP数组的循环方法 子问题数组 找到依赖关系

动态规划常见问题
1、动归基础
2、背包问题
  子问题:dp[i][j]表示取下标物品0-i 背包容量为j的最大价值
(1)0-1背包
  递推关系:dp[i][j]=(dp[i-1][j],dp[i-1][j-weight[i]]+price[i])
  vector<vector<int>> dp(thingNum,vector<int>(bagSize+1,0));    
  dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + price[i]);
(2)完全背包
  dp[i][j] = dp[i-1][j];   //不放i,初始化dp[i][j] 
  for (int k = 1; j - k * weight[i] >= 0;k++){   //下面是放多个i物品
      dp[i][j] = max(dp[i][j],dp[i-1][j-k*weight[i]] + k*price[i]);
  }
3、打家劫舍
 子问题:在偷下标为k间房的基础上,偷到的最大金额
 递推关系:dp[k]=max(dp[0]-dp[k-2])+nums[k];
4、子序列问题
(1)子问题:dp[i]找到以下标i结尾的最长递增子序列
   递推关系:dp[i]=dp[i-1]+1(条件:nums[i-1]<nums[i]) 否则dp[i]=1;
(2)子问题:以i结尾的乘积最大非空连续子数组
   递推关系:dpMax[i]=max(dpMax[i-1]*nums[i],dpMin[i-1]*nums[i]); 
   递推关系:dpMin[i]=min(dpMax[i-1]*nums[i],dpMin[i-1]*nums[i]);
5、完全平方数
 子问题:和为k的完全平方数的最少数量
 递推关系:dp[k]=min(1+dp[k-j*j]) j从(1-根号k)循环

回溯绝佳讲解

回溯要考虑的以下的点:
1、需要回头找用:vector<bool> used(n,false);
2、不能回头找用:int startIndex = 0;
3、多个数组使用:int index = 0;
3、在递归树上的收集情况:收集所有结点||收集叶子结点
4、判断递归结束的条件:什么时候叶节点可以终止
5、进行遍历用循环还是条件判断:数组元素少用条件判断,元素多用循环

//常用全局变量
vector<int> path;           //目前的路径的结果
vector<vector<int> > ans;   //返回的回溯的答案
vector<bool> used(n,false);  //选择过不能再次被选择用used记录元素访问情况

backtreaking(nums,used,0);

//回溯算法本身
void backtreaking(vector<int> nums,vector<bool> used,int startIndex,int index){
    //收获所有结果,进入一个递归就会收获结果
    ans.push_back(path);
    
    //if先处理终止条件 
    if(终止条件){
        //收集结果,叶子结点
        ans.push_back(path);
        return;
    }
    
    //遍历集合元素,如果遍历集合中只有两个元素(),那么就直接用if不用循环了,直接判断各种情况
    if(left==right && left<n) 
    if(left>right && left<n)
    
    for(int i=0/startIndex;i<nums[index].size();i++){        
        
        //处理结点,选择未访问结点加入路径
        if(used[i]==true) continue;
        used[i]=true;
        path.push_back(nums[i]);
        path.push_back(nums[index][i]);
        
        //递归函数
        backTreaking(nums,used);     //从头访问数组中不重复的元素
        backTracking(nums,i+1);      //访问数组的下一个元素
        backTracking(nums,index+1);  //访问下一个数组
        
        //回溯操作:对于path的修改
        path.pop_back();
        used[i]=false;    //used的处理
        sum=sum-nums[i];  //出递归条件的处理     
    }
    return;
}

DFS在网格中使用

//网格dfs模板
void dfs(vector<vector<char> >& grid, int row, int line) {
	//行列在范围内
	if (0<=row && row<grid.size() && 0<=line && line<grid[0].size()){
		//访问格子
		grid[row][line] = '2';
		dfs(grid, row - 1, line);//上
		dfs(grid, row + 1, line);//下
		dfs(grid, row, line - 1);//左
		dfs(grid, row, line + 1);//右
	}
	return;
}

BFS在网格中使用

//采用BFS可以用来求最短路径问题
int orangesRotting(vector<vector<int>>& grid) {

	int m = grid.size();
	int n = grid[0].size();
	queue<pair<int, int>> q;
	int count = 0;
	int newC = 0;

	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (grid[i][j] == 2) {
				q.push({ i,j });
			}
			else if (grid[i][j] == 1) {
				newC++;
			}
		}
	}

	if (newC == 0) return 0;

	while (!q.empty() && newC > 0) {
		int k = q.size();
		for (int i = 0; i < k; i++) {
			//出栈
			pair<int, int> p = q.front();
			q.pop();
			int x = p.first;
			int y = p.second;
			if (grid[x][y] == 1) {
				grid[x][y] = 2;
				newC--;
			}
			//上下左右入栈
			if (x - 1 >= 0 && grid[x - 1][y] == 1) q.push({ x - 1,y });
			if (x + 1 < m && grid[x + 1][y] == 1)  q.push({ x + 1,y });
			if (y - 1 >= 0 && grid[x][y - 1] == 1) q.push({ x,y - 1 });
			if (y + 1 < n && grid[x][y + 1] == 1)  q.push({ x,y + 1 });

		}
		count++;
	}
	if (newC == 0) {
		return count - 1;
	}
	else {
		return -1;
	}
}

零星知识点

1、判断一个数要在一个范围内要写成两个条件,比如:0<=row && row<grid.size()
2、unordered_map<int,int> m;
   m.insert(pair<int,int>(nums[i],i));
   m.count(target-nums[i])>0
   map<string,vector<string>> m;
3、map的遍历
for (map<int,int>::iterator it = m.begin(); it != m.end(); it++) {
	cout << it->first << it->second;
}
4int num1 = 123;
   string s = to_string(num1);    //数字转字符串
   int num2 = stoi(s);            //字符串转数字
   int num3 = '9'-'0';            //字符转数字
   (int)s[i]                      //字符转数字的ask码
   char c = (char)9;              //数字转字符
5printf("%.3f\n", c);           //double类型保留三位小数
6sort(v.begin(),v.end(),cmp);
   bool cmp(pair<double, double> a, pair<double, double> b){
	   return a.second / a.first < b.second / b.first; //单价低的优先
   }
7、润年:(year%4==0&&year%100!=0)||(year%400==0) 二月298、日期问题:月份天数直接打表写成数组
9、最大公约
int gcd(int a,int b) {
	if (b == 0) return a;
	return gcd(b,a%b);
}
10、最小公倍
int lcm(int a,int b) {
	int temp=gcd(a,b);
	return a*b/temp;
}
11、异或运算: 针对二进制同01 针对十进制偶数个消掉奇数个留下 找奇数个数用
   使用:ans=5^4^5; //ans=4
12、二分查找: 有可能找不到就<= 肯定能找到就< 适用于找数要求时间复杂度为O(logn)
13、快慢指针:1)当题目中要求只遍历一遍链表,就应该想到快慢指针,一般只需要定义两个变量即可
(2)把数组看成链表,运用快慢指针
14、递归思路: 递归函数是什么意思 边界条件是什么 相同步骤是什么
15、排版类问题
(1)一共有几行
(2)每行长度怎么变化
(3)每行什么时候开始打印

线性表衍生题目(初试)

相交链表

class Solution {
public:
    ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
        ListNode *l1=headA,*l2=headB,*retA=headA,*retB=headB;
        vector<int> conA,conB;
        int count=0;
        while(l1!=NULL){
            conA.push_back(l1->val);
            l1=l1->next;
        }
        while(l2!=NULL){
            conB.push_back(l2->val);
            l2=l2->next;
        }
        for(int i=conA.size()-1,j=conB.size()-1;i>=0&&j>=0;i--,j--){
            if(conA[i]==conB[j]){
                count++;
            }else{
                if(i==conA.size()-1){
                    return NULL;
                }
                break;
            }
        }
        for(int i=0;i<conA.size()-count;i++){
            retA=retA->next;
        }
        for(int i=0;i<conB.size()-count;i++){
            retB=retB->next;
        }
        while((&*retA)!=(&*retB)){
            retA=retA->next;
            retB=retB->next;
        }
        return retA;
    }
};

反转链表

//反转链表
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* ret=NULL,*temp=head;
        while(head!=NULL){
            head=head->next;
            temp->next=ret;
            ret=temp;
            temp=head;
        }
        return ret;
    }
};

回文链表

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<int> num;
        ListNode* list=head;
        while(head!=NULL){
            num.push_back(head->val);
            head=head->next;            
        }
        for(int i=0;i<num.size();i++){
            if(num[i]==num[num.size()-1-i]){
                ;
            }else{
                return false;
            }
        }
        return true;
    }
};

环形链表

class Solution {
public:
    bool hasCycle(ListNode *head) {
        unordered_set<ListNode*> num;
        ListNode* temp=head;
        int count=0;
        while(head!=NULL){
            count++;
            head=head->next;
            num.insert(temp);
            if(count!=num.size()){
                return true;
            }
            temp=head;
        }
        return false;
    }
};

环形链表II

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode*> s;   //ListNode结点的地址
        ListNode* temp=head;
        int len=0;
        int isUse=0;
        while(temp!=NULL){
            s.insert(temp);
            len++;
            if(s.size()!=len){
                len--;
                isUse=1;
                break;
            }
            temp=temp->next;
        }
        if(isUse==1){
            for(int i=0;i<len;i++){
                head=head->next;
            }
            return head;
        }else{
            return NULL;
        }
    }
};

合并两个有序链表

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* list=NULL,* head=NULL,*temp1=list1,*temp2=list2;
        int flag=0;
        while(list1!=NULL&&list2!=NULL){
            if(list1->val<list2->val){
                if(flag==0){
                    list=temp1;
                    head=list;
                    flag=1;
                }else{
                    list->next=temp1;
                    list=temp1;
                }
                list1=list1->next;
                temp1->next=NULL;
                temp1=list1;
                
            }else{  
                if(flag==0){
                    list=temp2;
                    head=list;
                    flag=1;
                }else{
                    list->next=temp2;
                    list=temp2;
                }
                list2=list2->next;
                temp2->next=NULL;
                temp2=list2;
            }
        }
        if(list1!=NULL){
            if(list==NULL){
                list=list1;
                head=list;
            }else{
                list->next=list1;
            }
        }else if(list2!=NULL){
            if(list==NULL){
                list=list2;
                head=list;
            }else{
                list->next=list2;
            }
        }
        return head;
    }
};

二叉树衍生题目(初试)

二叉树的中序遍历

class Solution {
public:
    vector<int> out;
    vector<int> inorderTraversal(TreeNode* root) {
        visit(root);
        return out;
    }
    void visit(TreeNode* root){
        if(root!=NULL){
            visit(root->left);
            out.push_back(root->val);
            visit(root->right);
        }
    }
};

二叉树的最大深度

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root!=NULL){
            int leftLen=maxDepth(root->left);
            int rightLen=maxDepth(root->right);
            return leftLen>rightLen ? leftLen+1:rightLen+1;
        }else{
            return 0;
        }
    }
};

翻转二叉树

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(root!=NULL){
            TreeNode* left=invertTree(root->left);
            TreeNode* right=invertTree(root->right);
            root->left=right;
            root->right=left;
            return root;
        }else{
            return NULL;
        }
    }
};

对称二叉树

class Solution {
public:
    bool isSymmetric(TreeNode* root){
        return isMirror(root->left,root->right);
    }
    bool isMirror(TreeNode* root1,TreeNode* root2) {
        if(root1!=NULL&&root2!=NULL){
            if(root1->val!=root2->val){
                return false;
            }
            bool flag1=isMirror(root1->left,root2->right);
            bool flag2=isMirror(root2->left,root1->right);
            if(flag1==true&&flag2==true){
                return true;
            }else{
                return false;
            }
        }else{
            if(root1==NULL&&root2==NULL){
                return true;
            }else{
                return false;
            }
        }
    }
};

二叉树的直径

class Solution {
public:
    int ans;
    int depth(TreeNode* rt){
        if (rt==NULL) {
            return 0; // 访问到空节点了,返回0
        }
        int L=depth(rt->left); // 左儿子为根的子树的深度
        int R=depth(rt->right); // 右儿子为根的子树的深度
        ans=max(ans,L+R+1); // 计算d_node即L+R+1 并更新ans
        return max(L,R)+1; // 返回该节点为根的子树的深度
    }
    int diameterOfBinaryTree(TreeNode* root) {
        ans=1;
        depth(root);
        return ans-1;
    }
};

二叉树的层序遍历

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        
        //父节点入栈
        queue<TreeNode*> q;
        vector<vector<int> > ans;
        vector<int> v;

        //处理空树
        if(root==NULL) return ans;
        q.push(root);

        while(!q.empty()){
            int n=q.size();
            for(int i=0;i<n;i++){   //为了一口气处理完,队列里面的
                TreeNode* temp=q.front();
                q.pop();
                v.push_back(temp->val);
                if(temp->left!=NULL)  q.push(temp->left);
                if(temp->right!=NULL)  q.push(temp->right);
            }
            ans.push_back(v);
            v.clear();
        }
        return ans;
    }
};
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值