目录
面试榜单
NC65 斐波那契数列
题目描述:
分析:
使用递归求解,当输入参数等于1、2时返回整数1
class Solution {
public:
int Fibonacci(int n) {
if(n == 1 || n == 2)
{
return 1;
}
return Fibonacci(n-1) + Fibonacci(n-2);
}
};
NC103 反转字符串
题目描述:
分析:
使用string迭代器逆向打印存入字符串返回
#include<string>
class Solution {
public:
string solve(string str) {
string s;
string::reverse_iterator rit = str.rbegin();
while(rit != str.rend())
{
s.push_back(*rit);
++rit;
}
return s;
}
};
NC4 判断链表中是否有环
分析:
定义两个指针一开始都指向头节点,区别在于步长不同,一快一慢。
slow 指针每次向后移动一个位置,而fast 指针向后移动两个位置。如果链表中存在环,则 fast 指针最终将再次与 slow 指针在环中相遇。
如果不存在环,则fast指针会指向nullptr,则返回false
class Solution {
public:
int Fibonacci(int n) {
if(n == 1 || n == 2)
{
return 1;
}
return Fibonacci(n-1) + Fibonacci(n-2);
}
};
————————————————
版权声明:本文为CSDN博主「halooy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_49619206/article/details/134290089
NC141 判断是否为回文字符串
题目描述:
分析:
先找到首字符strat和最后一个字符end的位置
然后进行比较,如果不相等直接返回false
如果相等,则++start,–end
当start大于等于end时,则正常结束,跳出循环,返回true
class Solution {
public:
bool judge(string str) {
//首字符索引
char start = 0;
//最后一个字符索引
char end = str.size()-1;
while(start < end)
{
if(str[start] != str[end])
{
return false;
}
++start;
--end;
}
return true;
}
};
NC151 最大公约数
题目描述:
分析:
定义一个变量tmp用来存储a,b中较小的数。
然后用a,b对tmp进行取余,如果有余数,则对tmp进行–操作。
直到被a,b两数整除则为a,b的最大公约数。返回该值。
class Solution {
public:
int gcd(int a, int b) {
int tmp = (a>b)? b:a;
while(tmp)
{
if(a%tmp == 0 && b%tmp == 0)
{
return tmp;
}
--tmp;
}
return 1;
}
};
NC7 买卖股票的最好时机(一)
题目描述:
分析1(动态规划):
思路:对于每一天都有两个状态:到此为止的最大收益和是否持股。
因此用:
dp[i][0]表示第i天不持股到该天为止的最大收益,
dp[i][1]表示第i天持股,到该天为止的最大收益。
然后对于之后的每一天,都根据前一天的情况进行赋值。
如果当天不持股,有可能是前面的若干天中卖掉了或是还没买,因此到此为止的总收益和前一天相同,也有可能是当天才卖掉;
如果当天持股,有可能是前面若干天中买了股票,当天还没卖,因此收益与前一天相同,也有可能是当天买入,此时收益为负的股价。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<vector<int>> dp(n, vector<int>(2, 0));
//第一天不持股收益
dp[0][0] = 0;
//第一天持股收益
dp[0][1] = -prices[0];
for(int i = 1; i < n; ++i)
{
//第i天不持股最大收益:
//1.前一天也不持股,前几天卖掉或者没买,收益和前一天相同
//2.前一天持股,第i天当天抛出,收益为前一天持股加上当天抛出
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);
//第i天持股最大收益:
//1.前一天不持股,第i天当天买入,收益为当天买入价格的负数
//2.前一天持股,收益和前一天相同
dp[i][1] = max(-prices[i], dp[i-1][1]);
}
//最后一天不持股,到改天为止的最大收益
return dp[n-1][0];
}
};
分析2(贪心思想):
思路:如果在某一天卖出了股票,那么要想收益最高,一定是它前面价格最低的那天买入的股票才可以。因此可以利用贪心思想解决,每次都将每日收入与最低价格相减维护最大值。
将第一天看成价格最低,后续遍历的时候遇到价格更低则更新价格最低。
每次都比较最大收益与当日价格减去价格最低的值,选取最大值作为最大收益。
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param prices int整型vector
* @return int整型
*/
int maxProfit(vector<int>& prices) {
// write code here
int n = prices.size();
if(n == 0)
return 0;
//最大收益
int maxProfit;
//当天最大收益
int max_td;
//截至当天最低价格,将第一天看作价格最低
int lessPrice = prices[0];
//买入必须是卖出前一天
maxProfit = 0;
for(int i = 1; i < n; ++i)
{
//第i天的最大收益,当天价格减去先前最低价格
max_td = prices[i]-lessPrice;
//如果第i天的最大收益比之前的大,则更新最大收益
maxProfit = max(maxProfit, max_td);
//如果先前最低价格大于第i天的价格,则更新最低价格
//由于买入必须是卖出前一天,因此先计算第i天的最大收益后再更新最低价格
lessPrice = min(lessPrice, prices[i]);
}
return maxProfit;
}
};
NC9 二叉树中和为某一值的路径(一)
题目描述:
分析1(递归):
从根节点遍历到叶子,在根节点每次往下一层的时候,将sum减去节点值,最后检查是否完整等于0。终止条件: 每当遇到节点为空,意味着过了叶子节点,返回。每当检查到某个节点没有子节点,它就是叶子节点,此时sum减去叶子节点值刚好为0,说明找到了路径。
返回值: 将子问题中是否有符合新目标值的路径层层往上返回。
本级任务: 每一级需要检查是否到了叶子节点,如果没有则递归地进入子节点,同时更新sum值减掉本层的节点值。
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @param sum int整型
* @return bool布尔型
*/
bool hasPathSum(TreeNode* root, int sum) {
// write code here
if(root == nullptr)
return false;
if(root->left == nullptr && root->right == nullptr && sum-root->val == 0)
return true;
return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right,sum-root->val);
}
};
分析2(深度优先搜索dfs):
首先检查空间点,空树没有路径;
栈每次保存一个pair类型数据,包含两个值,一个值记录节点,一个值记录到该节点位置的路径和;
遍历过程中,每次弹出栈顶元素,判断是否是叶子节点并且路径和是否等于目标值;
没有到叶子节点就将左右子节点(如果有)加入栈中,并跟随加入路径和;
如果遍历结束也没有找到路径和,则该二叉树中没有。
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
#include <cstdio>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @param sum int整型
* @return bool布尔型
*/
bool hasPathSum(TreeNode* root, int sum) {
// write code here
if (root == nullptr)
return false;
//建立栈
stack<pair<TreeNode*, int>> s;
//将根节点及根节点的值压入
s.push({root, root->val});
while (!s.empty())
{
//给栈顶元素赋值
auto temp = s.top();
//去除栈顶元素
s.pop();
//如果栈顶元素的左右子树都空,并且累加值等于sum则返回true
if (temp.first->left == nullptr && temp.first->right == nullptr && temp.second == sum)
{
return true;
}
//如果左子树非空,则将左子树压入,并将左子树的值进行累加
if (temp.first->left != nullptr)
{
s.push({temp.first->left, temp.second + temp.first->left->val});
}
//如果右子树非空,则将右子树压入,并将右子树的值进行累加
if (temp.first->right != nullptr)
{
s.push({temp.first->right, temp.second + temp.first->right->val});
}
}
return false;
}
};
NC11 将升序数组转化为平衡二叉搜索树
题目描述:
分析(递归):
返回值为当前节点为根节点的平衡二叉树;
由于给定一个升序数组,递归函数的参数应为数据的左右边界;
根节点数值应为给定边界的中点的值;
递归左右子树建树。
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* };
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return TreeNode类
*/
TreeNode* dfs(vector<int>& nums, int left, int right)
{
//结束条件:
if(left > right)
return nullptr;
//定义数据中间位置:即根节点
int mid = (left + right + 1)/2;
//根据mid值创建根节点
TreeNode* root = new TreeNode(nums[mid]);
//遍历左子树
root->left = dfs(nums, left, mid-1);
//遍历右子树
root->right = dfs(nums, mid+1, right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
// write code here
int len = nums.size();
return dfs(nums, 0, len-1);
}
};
others
输出数组中第k小的数
题目描述:
给定一个数组arr 输出数组中第k小的数
如果不存在 输出-1
输入格式:
第一行输入一个数字n 代表数组arr大小
第二行依次输入n个数
第三行输入一个数字k
输出格式:
输出数组中第k小的数 如果不存在 输出-1
测试样例:
分析:
根据set容器去重的特性以及set容器内部按照从小到大的顺序排列
将数组内所有元素输入到set容器内,然后对set迭代器进行遍历,如果遍历到第k个元素存在则存在第k小的数,进行输出;如果不存在,也就是迭代器到end的位置,则输出-1。举例:
数组元素:3 3 2
set容器:2 3
如果k=2,则输出3
如果k=3,此时set迭代器遍历到end()的位置,不存在该数据,则输出-1
#include<iostream>
#include<set>
using namespace std;
int main()
{
//数组大小
int n;
//定义第k小的数
int kmin;
cin >> n;
int *arr = new int[n];
//给数组元素传值
for (int i = 0; i < n; ++i)
{
cin >> arr[i];
}
//数组传入set容器
set<int> s(arr, arr + n);
cin >> kmin;
//用来记录遍历位置
int count = 1;
set<int>::iterator it = s.begin();
while (it != s.end())
{
//如果第k小的数存在则输出该值,跳出循环
if (count == kmin)
{
cout << *it;
break;
}
++it;
++count;
}
//如果循环正常结束,则第k个值不存在,输出-1
if (it == s.end())
{
cout << -1 << endl;
}
delete[] arr;
return 0;
}
在数组内找出查找数字在该数组第一次出现的索引
题目描述
给定一个长度为N的单调不递减整数数组 arr,进行Q次询问。对于每次询问,给出一个整数X,要求找出X在arr中第一次出现的下标,如果X未在数组中出现过,则输出-1。
输入格式
第一行输入两个整数N,Q 其中N 代表数组 arr 长度,Q代表询问次数
第二行输入N个整数 用空格分开
第三行输入Q个整数 用空格分开
输出格式
在一行中输出Q次查询的结果 每个整数用空格分开
分析:
用三个数组分别记录要查询的值,被查询的值,值在给定数组的索引。
首先给出最简单遍历的方法,该方法时间复杂度较高
int main()
{
int n,q;
cin >> n >> q;
//数组元素放入arr
int* arr = new int[n];
for(int i = 0; i < n; ++i)
{
cin >> arr[i];
}
//查询元素放入arr_q
int* arr_q = new int[q];
for(int i = 0; i < q; ++i)
{
cin >> arr_q[i];
}
//查询结果放入result
int* result = new int[q];
for(int i = 0; i < q; ++i)
{
int Q = arr_q[i];
int idx = -1;
for(int j = 0; j < n; ++i)
{
if(arr[j] == Q)
{
idx = j;
break;
}
}
result[i] = idx;
}
for(int i = 0; i < q; ++i)
{
cout << result[i] << " ";
}
cout << endl;
delete[] arr;
delete[] arr_q;
delete[] result;
return 0;
}
方法二:
上述方法在面对数据量大时时间复杂度过高,可以使用二分查找降低查询次数。
#include<iostream>
using namespace std;
int binarySearch(int* arr, int n, int Q)
{
int left = 0;
int right = n - 1;
int idx = -1;
while(left <= right)
{
int mid = (right + left)/2;
if(arr[mid] == Q)
{
idx = mid;
right = mid - 1;
}
else if(arr[mid] > Q)
{
right = mid - 1;
}
else if(arr[mid] < Q)
{
left = mid + 1;
}
}
return idx;
}
int main()
{
int n,q;
cin >> n >> q;
//数组元素放入arr
int* arr = new int[n];
for(int i = 0; i < n; ++i)
{
cin >> arr[i];
}
//查询元素放入arr_q
int* arr_q = new int[q];
for(int i = 0; i < q; ++i)
{
cin >> arr_q[i];
}
int* result = new int[q];
for(int i = 0; i < q; ++i)
{
int Q = arr_q[i];
int idx = binarySearch(arr, n, Q);
result[i] = idx;
}
for(int i = 0; i < q; ++i)
{
cout << result[i] << " ";
}
cout << endl;
delete[] arr;
delete[] arr_q;
delete[] result;
return 0;
}
计算每个节点的字数包含节点数
题目描述
给定一棵以1为根,包含N个节点的树,每个节点都有一个唯一的编号。请计算每个节点的子树中包含的节点数,包括节点本身。
输入格式
第一行包含一个正整数n,表示树的节点个数。
接下来的n-1行,每行包含一个正整数p,表示节点i的父节点的值。
输出格式
n个整数,每个整数用空格分开
第i个数为节点i的子节点个数(包括他自己)
分析:
通过建立二维数组
第一维存储树的每个节点
第二维存放每个节点的子节点
通过遍历树的节点来解决,统计每个节点的子节点数(包括自身)。使用深度优先搜索(DFS)算法。
#include<iostream>
#include<vector>
using namespace std;
//存储每个节点
vector<vector<int>> tree;
//存储每个节点及其子树的个数
vector<int> subtree_size;
void dfs(int node)
{
subtree_size[node] = 1;
for(int child : tree[node])
{
dfs(child);
subtree_size[node] += subtree_size[child];
}
}
int main()
{
//树的节点个数
int n;
cin >> n;
//存储每个节点
tree.resize(n+1);
//存储每个节点及其子树的个数
subtree_size.resize(n+1);
int parent;
for(int i = 2; i <= n; ++i)
{
cin >> parent;
tree[parent].push_back(i);
}
dfs(1);
for(int i = 1; i <= n; ++i)
{
cout << subtree_size[i] << " ";
}
cout << endl;
return 0;
}