开设本专栏的原因:
由于九月将至,然而我的上机水平还不够所以临时抱佛脚了。当前目标是将BFS和DFS成功上手。
注意的是:基础理论方面已经很熟悉了,所以我现在直接从上手代码开始。
一、Leecode T993入门
从二叉树开始,慢慢来~
题意:写一个函数判断输入的两个数在树中是不是不同一个父节点但是层数相同,如果是就返回true,否则返回false。
值得注意的是这是我第一次写非ACM类型的题目,上手有点困难。
Code:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int xparent,xdeep,yparent,ydeeep;//通过全局变量获得x和y的父节点和深度
void dfs(TreeNode* node,int deepth,int x,int y,int parent){//dfs实现,这里parent存的是节点值,node是该节点的pointer,本函数就是用来判断是否该节点与父节点即parent相等,如果是就保存节点信息。
if(node == nullptr){
return;
}
if(node -> val == x){
xparent = parent;
xdeep = deepth;
}else if(node -> val == y){
yparent = parent;
ydeeep = deepth;
}
else{
dfs(node->left,deepth+1,x,y,node->val);
dfs(node->right,deepth+1,x,y,node->val);
}
}
bool isCousins(TreeNode* root, int x, int y) {
//注意起点!root本身不需要判断。
dfs(root->left,1,x,y,root->val);
dfs(root->right,1,x,y,root->val);
if((xdeep == ydeeep) && (xparent!=yparent)){
return true;
}else{
return false;
}
}
};
二、洛谷P1030 NOIP2001
在上手了力扣类型的题目后决定再用ACM赛制。
绝对的入门题,给与二叉树的中序序列和后序序列,写出前序序列
专业知识:对于一个二叉树,如果只给前序和后序是没办法确定一棵树的。
思路:
- 明显的是此处如果用单纯的字符串处理会非常麻烦,所以对于程序员来说需要有递归的思想。
- 该题的DFS体现在它是先左子树后右子树的方式进行遍历的,所以是DFS。注意的是,递归输出的应该是后序序列,而不是中序序列。
- 这里有一个问题,就是关于在获得中序序列中父节点坐标以后如何处理得到左右子树的问题右子树如何生成这个问题非常非常真的重要!
Code
#include <bits/stdc++.h>
#include <cstdio>
#define Max 10001
using namespace std;
int length;//因为前后中序列得到的都是一个相同的长度的序列,所以length就是存该信息的
char strMid[10],strEnd[10];
int getPosition(char x){//在中序序列中获取目前确认为父节点的节点的位置
for(int i = 0; i < length; i++){
if(strMid[i] == x){
return i;
}
}
}
void dfs(int ms,int me,int as,int ae){
if(ms > me) return;
cout<<strEnd[ae];
int position = getPosition(strEnd[ae]);
dfs(ms,position-1,as,as+position-ms-1);
dfs(position+1,me,as+position-ms,ae-1);
}
int main(){
cin>> strMid;
cin>> strEnd;
length = strlen(strMid);//如何处理获取到字符串的长度
dfs(0,length-1,0,length-1);
}
三、洛谷P1036 NOIP2002
题目大意:给n个数,和一个整数k。即在n个数中找到k个数进行相加,判断有几个相加后的和为素数。
该题的重点就在于如何快速地从n个数中找到k个数。如果用纯dfs的方法来计算,就是每一次都判断我们是否选择该数加入到当前的和里面来,两种情况的dfs
知识点:sqrt()函数非常慢,一般在需要使用平方时候用i*i<n来计算。
#include <bits/stdc++.h>
#include <cstdio>
#define Max 10001
using namespace std;
int num[25];
int n,k,res = 0;
bool isprime(int x){ //判断素数
for(int i = 2;i * i <x;i ++){
if(x%i == 0) return false;
}
return true;
}
int dfs(long long sum,int x,int remain){//参考别人的题解,我们对于每次加一个数我们可以选择加或者不加。
if(remain == k){
if(isprime(sum)) res++;
}
else if(x < n){
dfs(sum,x+1,remain);
dfs(sum+num[x],x+1,remain+1);
}
}
int main(){
cin>>n;cin>>k;
for(int i = 0;i < n;i ++){
cin>>num[i];
}
dfs(0,0,0);
cout<<res;
}
对于该题,洛谷最佳回答是一个类似于枚举的递归,贴码如下:
#include<iostream>
#include<math.h>
using namespace std;
int x[20],n,k;//依照题目所设
bool isprime(int n){//判断是否质数
int s=sqrt(double(n));
for(int i=2;i<=s;i++){
if(n%i==0)return false;
}
return true;
}
int rule(int choose_left_num,int already_sum,int start,int end){//choose_left_num为剩余的k,already_sum为前面累加的和,start和end为全组合剩下数字的选取范围;调用递归生成全组合,在过程中逐渐把K个数相加,当选取的数个数为0时,直接返回前面的累加和是否为质数即可
if(choose_left_num==0)return isprime(already_sum);
int sum=0;
for(int i=start;i<=end;i++){
sum+=rule(choose_left_num-1,already_sum+x[i],i+1,end);
}
return sum;
}
int main(){
cin>>n>>k;
for(int i =0;i<n;i++)cin>>x[i];
cout<<rule(k,0,0,n-1);//调用递归解决问题
}
总结今天:虽然都参考了博客,但是很久没有入手算法了也算是情有可原。今天之后需要知道的知识点:1.如何用代码遍历二叉树,记录深度。2.如何由后序序列和中序序列求出前序序列,当然一举反三的是在知道前序和中序时如何求出后序。该题如何生成左右子树非常重要。3.如何组合从n个数中选出k个数的组合。