京东
字符串1
给出m个字符串S1,S2,…,Sm和一个单独的字符串T。请在T中选出尽可能多的子串同时满足: 1)这些子串在T中互不相交。 2)这些子串都是S1,S2,…,Sm中的某个串。 问最多能选出多少个子串。
输入描述:
第一行一个数m(1≤m≤10),接下来m行,每行一个串。最后一行输入一个串T。输入中所有单个串的长度不超过100000,串中只会出现小写字母。
输出描述:
输出一个数,最多能选出多少串。
输入例子1:
3
aa
b
ac
bbaac
输出例子1:
3
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class compare_vector_1_less {
public:
//按第二列大小从大到小排列
bool operator () (const vector<int>& a, const vector<int>& b) {
return a[1] < b[1];
}
};
int main() {
int n = 0;
cin >> n;
vector<string> str_set(n);
for (int i = 0; i < n; i++)
{
cin >> str_set[i];
}
string str_obj;
cin >> str_obj;
vector<vector<int>> range;
//得到子串所在的区间
for (int i = 0; i < n; i++)
{
int start_index = 0;
string::size_type temp = str_obj.find(str_set[i], start_index);
while (temp != string::npos)
{
vector<int> range_temp(2);
range_temp[0] = temp;
range_temp[1] = temp + str_set[i].size() - 1;
range.push_back(range_temp);
start_index = range_temp[1] + 1;
temp = str_obj.find(str_set[i], start_index);
}
}
//用贪心算法求解最大不相交区间的集合
sort(range.begin(), range.end(), compare_vector_1_less());
int max_res = 0;
int start = 0;
for (int i = 0; i < range.size(); i++)
{
if (range[i][0] >= start) {
max_res++;
start = range[i][1] + 1;
}
}
cout << max_res << endl;
//system("pause");
return 0;
}
两个子串
给定一个字符串s, 请计算输出含有连续两个s作为子串的最短字符串。 注意两个s可能有重叠部分。例如,“ababa"含有两个"aba”.
输入描述:
输入包括一个字符串s,字符串长度length(1 ≤ length ≤ 50),s中每个字符都是小写字母.
输出描述:
输出一个字符串,即含有连续两个s作为子串的最短字符串。
输入例子1:
abracadabra
输出例子1:
abracadabracadabra
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
int l = s.length();
int k=0 ;
for (int i = 1; i < l; i++) {
if (s[i] == s[0]) {
string s1 = s.substr(i);
string s2 = s.substr(0, l - i );
if (s1 == s2) {
k = s1.size();
break;
}
}
}
cout << s + s.substr(k) << endl;
return 0;
}
华为
有一个数组a[N]顺序存放0~N-1,要求每隔两个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。以8个数(N=7)为例:{0,1,2,3,4,5,6,7},0->1->2(删除)->3->4->5(删除)->6->7->0(删除),如此循环直到最后一个数被删除。
输入描述:
每组数据为一行一个整数n(小于等于1000),为数组成员数,如果大于1000,则对a[999]进行计算。
输出描述:
一行输出最后一个被删掉的数的原始下标位置。
输入例子1:
8
输出例子1:
6
思路:用队列模拟,队首取数,用一个计数器计数,隔2个删一个,其他的重新放到队尾
#include<queue>
#include<iostream>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
queue<int> q;
for(int i=0;i<n;i++)
{
q.push(i);
}
int count=0;
while(q.size()!=1)
{
if(count!=2)
{
int b=q.front();
q.pop();
q.push(b);
count++;
}
else
{
q.pop();
count=0;
}
}
int c=q.front();
cout<<c<<endl;
}
return 0;
}
安置路灯
题目描述
小Q正在给一条长度为n的道路设计路灯安置方案。
为了让问题更简单,小Q把道路视为n个方格,需要照亮的地方用’.'表示, 不需要照亮的障碍物格子用’X’表示。
小Q现在要在道路上设置一些路灯, 对于安置在pos位置的路灯, 这盏路灯可以照亮pos - 1, pos, pos + 1这三个位置。
小Q希望能安置尽量少的路灯照亮所有’.'区域, 希望你能帮他计算一下最少需要多少盏路灯。
输入描述:
输入的第一行包含一个正整数t(1 <= t <= 1000), 表示测试用例数
接下来每两行一个测试数据, 第一行一个正整数n(1 <= n <= 1000),表示道路的长度。
第二行一个字符串s表示道路的构造,只包含’.‘和’X’。
输出描述:
对于每个测试用例, 输出一个正整数表示最少需要多少盏路灯。
示例1
输入
复制
2
3
.X.
11
…XX…XX
输出
复制
1
3
思路:贪心算法:
链接:https://www.nowcoder.com/questionTerminal/3a3577b9d3294fb7845b96a9cd2e099c?answerType=1&f=discussion
来源:牛客网
考察点:贪心
分析:
对于这道题来说,如果在第i个位置上安装路灯,那么它能够照亮的地方就是i-1, i和i+1,那么安装路灯最少的方法就是在三个位置的中间设置路灯,即如果第i个位置为’.’, 那么显然在 i+1 处安装路灯是最好的,它可以照到位置i, i+1和i+2,这样能够最大程度的减少路灯的数目。
例如下图:
算法实现:
(1) 设置遍历指针i=0;
(2) 如果第i个位置为’.’,ans++(在i+1处放置路灯,可以照亮i, i+1, i+2),然后从第i+3位置处继续遍历,即i=i+3;
(3) 如果第i个位置为’x’,那么指针i++。
(4) 一直遍历字符串末尾结束,最后输出ans即可。
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(1)
#include<iostream>
using namespace std;
int main() {
int m;
cin >> m;
while (m--) {
string str;
int nums;
cin >> nums;
cin >> str;
int count = 0;
int point = 0;
while(point<=str.size()){
if (str[point] == '.') {
point += 3;
count++;
}
else
{
point += 1;
}
}
cout << count << endl;
}
}
牛牛找工作
题目描述
为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。牛牛的小伙伴太多了,于是他只好把这个任务交给了你。
输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)。
接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)。
接下来的一行包含M个正整数,分别表示M个小伙伴的能力值Ai(Ai<=1000000000)。
保证不存在两项工作的报酬相同。
输出描述:
对于每个小伙伴,在单独的一行输出一个正整数表示他能得到的最高报酬。一个工作可以被多个人选择。
示例1
输入
复制
3 3
1 100
10 1000
1000000000 1001
9 10 1000000000
输出
复制
100
1000
1001
思路:链接:https://www.nowcoder.com/questionTerminal/46e837a4ea9144f5ad2021658cb54c4d?f=discussion
来源:牛客网
将职位的能力和薪水放入map中,key为能力,value为薪水,在map中就会根据key自动排序了~
结合make_pair把找工作的人也加入到map中,这样就可以一起排序了。
在map中遍历(按能力排序好了),将map->second(value)值的含义改为map->first(能力)值以内最多有多少薪水,然后按每个小伙伴的能力直接输出就好啦。
#include<iostream>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
int main() {
int numWorks;
int numNumbers;
map<int,int >mymap;
cin >> numWorks >> numNumbers;
while (numWorks--) {
int nengLi = 0;
int wages = 0;
cin >> nengLi >> wages;
mymap[nengLi] = wages;
}
vector<int>fellow(numNumbers, 0);
for (int i = 0; i < numNumbers; i++) {
cin >> fellow[i];
}
for (int i = 0; i < fellow.size(); i++) {
if (mymap.count(fellow[i]) == 0) {
mymap.insert(make_pair(fellow[i], -1));
}
}
int nowMax = 0;
for (map<int, int>::iterator it = mymap.begin(); it!= mymap.end(); it++) {
if (it->second >= nowMax)nowMax = it->second;
else{
it->second = nowMax;
}
}
for (int i = 0; i < fellow.size(); i++) {
cout << mymap[fellow[i]] << endl;
}
}
被3整除
题目描述
小Q得到一个神奇的数列: 1, 12, 123,…12345678910,1234567891011…。
并且小Q对于能否被3整除这个性质很感兴趣。
小Q现在希望你能帮他计算一下从数列的第l个到第r个(包含端点)有多少个数可以被3整除。
输入描述:
输入包括两个整数l和r(1 <= l <= r <= 1e9), 表示要求解的区间两端。
输出描述:
输出一个整数, 表示区间内能被3整除的数字个数。
示例1
输入
复制
2 5
输出
复制
3
说明
12, 123, 1234, 12345…
其中12, 123, 12345能被3整除。
#include<iostream>
using namespace std;
int main() {
int l, r;
while(cin >> l >> r){
int ans1 = 2 * (l-1) / 3;
int ans2 = 2 * r / 3;
cout << ans2 - ans1 << endl;
}
}
矩阵重叠
题目描述
平面内有n个矩形, 第i个矩形的左下角坐标为(x1[i], y1[i]), 右上角坐标为(x2[i], y2[i])。
如果两个或者多个矩形有公共区域则认为它们是相互重叠的(不考虑边界和角落)。
请你计算出平面内重叠矩形数量最多的地方,有多少个矩形相互重叠。
输入描述:
输入包括五行。
第一行包括一个整数n(2 <= n <= 50), 表示矩形的个数。
第二行包括n个整数x1[i](-10^9 <= x1[i] <= 10^9),表示左下角的横坐标。
第三行包括n个整数y1[i](-10^9 <= y1[i] <= 10^9),表示左下角的纵坐标。
第四行包括n个整数x2[i](-10^9 <= x2[i] <= 10^9),表示右上角的横坐标。
第五行包括n个整数y2[i](-10^9 <= y2[i] <= 10^9),表示右上角的纵坐标。
输出描述:
输出一个正整数, 表示最多的地方有多少个矩形相互重叠,如果矩形都不互相重叠,输出1。
示例1
输入
2
0 90
0 90
100 200
100 200
输出
2
方法:枚举
分析:
注意一点题目要求的是平面内重叠矩形数量最多的地方,有多少个矩形相互重叠?那么对于这个题目来说,正常的循环遍历方法是无法轻易解决的,那么我们换种方法,我们想办法将这n个矩形所包含的点全部枚举出来,然后在检查看有多少个矩形包含这个点,输出包含点最多的矩形个数值即可。
举个例子:现在有两个矩形,第一个矩形的左下角坐标为(0,0)右上角坐标为(6,6),第二个矩形的左下角坐标为(5,5)右上角坐标为(10,10),那么我们将这两个矩形所包含的点列举出来:{(0,0),(0,5),(0,6),(0,10),(5,0),(5,5),(5,6),(5,10),(6,0),(6,5),(6,6),(6,10),(10,0),(10,5),(10,6),(10,10)} 一共16个点,然后就枚举这16个点,对于第i个点来说,看一下到底有多少个矩形包含这个点,记录包含矩形的个数,最后取最大值。
算法实现:首先我们要获取n个矩形可能包含的点,那么我们将所有的x坐标列出来,所有的y坐标列出来,那么所包含的点(x,y)也就随之列举出来了,一共是2n*2n个点,然后对于这个点我们判断在n个矩形中到底有多少个矩形包含(x,y)坐标点,判断的方式为:如果满足条件,那么(x,y)就属于以(x1,y1)为左下角,(x2,y2)为右上角的矩形,记录结果加一,遍历n遍以后,比较最大值输出即可。
Tips:矩形A与矩形B重叠,矩形B与矩形C重叠,但是不意味着矩形A与矩形C也重叠。
2. 复杂度分析:
时间复杂度:O(n^3)
空间复杂度:O(n)
#include<iostream>
#include<cstring>
using namespace std;
struct {
int x1, y1, x2, y2;
}a[55];
int x[150], y[150];
int main() {
int n;
while (cin >> n) {
int cntx = 0;
int cnty = 0;
for (int i = 0; i < n; i++) {
cin >> a[i].x1;
x[cntx++] = a[i].x1;
}
for (int i = 0; i < n; i++) {
cin >> a[i].y1;
y[cnty++] = a[i].y1;
}
for (int i = 0; i < n; i++) {
cin >> a[i].x2;
x[cntx++] = a[i].x2;
}
for (int i = 0; i < n; i++) {
cin >> a[i].y2;
y[cnty++] = a[i].y2;
}
int ans = 0;
for (int i = 0; i < cntx; i++) {
for (int j = 0; j < cnty; j++) {
int count = 0;
for (int k = 0; k < n; k++) {
if (x[i]>=a[k].x1&&x[i]<a[k].x2&&y[j]>=a[k].y1&&y[j]<a[k].y2) {
count++;
}
}
ans = max(count, ans);
}
}
cout<< ans << endl;
}
}
获得最多的奖金
题目描述
小明在越南旅游,参加了当地的娱乐活动。小明运气很好,拿到了大奖, 到了最后的拿奖金环节。小明发现桌子上放着一列红包,每个红包上写着奖金数额。
现在主持人给要求小明在这一列红包之间“切”2刀,将这一列红包“切”成3组,并且第一组的奖金之和等于最后一组奖金和(允许任意一组的红包集合是空)。最终第一组红包的奖金之和就是小明能拿到的总奖金。小明想知道最多能拿到的奖金是多少,你能帮他算算吗。
举例解释:桌子上放了红包 1, 2, 3, 4, 7, 10。小明在“4,7”之间、“7,10” 之间各切一刀,将红包分成3组 [1, 2, 3, 4] [7] [10],其中第一组奖金之和=第三组奖金之和=10,所以小明可以拿到10越南盾。
输入描述:
第一行包含一个正整数n,(1<=n<= 200 000),表示有多少个红包。
第二行包含n个正整数d[i],表示每个红包包含的奖金数额。其中1<= d[i] <= 1000 000 000
输出描述:
小明可以拿到的总奖金
示例1
输入
5
1 3 1 1 4
输出
5
说明
[1,3,1] [ ] [1,4] ,其中第一组奖金和是5,等于第三组奖金和。所以小明可以拿到5越南盾
示例2
输入
5
1 3 2 1 4
输出
4
说明
[1,3] [2,1] [4],小明可以拿到4越南盾
示例3
输入
3
4 1 2
输出
0
说明
[ ] [4, 1, 2] [ ] ,小明没办法,为了保证第一组第三组相等,只能都分成空的。所以小明只能拿到0越南盾。
思路:双指针
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<unordered_set>
#include<set>
#include<map>
#include<unordered_map>
#include<queue>
#include<stack>
#include<cctype>
#include<string>
#include<regex>
#include<valarray>
using namespace std;
class Solution {
public:
void method(vector<int>datasets) {
int left = 0;
int right = datasets.size()-1;
long res = 0;
long sum1 = 0;
long sum2 = 0;
while (left <= right) {
if (sum1 < sum2) {
sum1 += datasets[left++];
}
else if (sum1 > sum2) {
sum2 += datasets[right--];
}
else {
sum1 += datasets[left++];
sum2 += datasets[right--];
//res = max(sum1, res);
}
if (sum1 == sum2) {
res = max(sum1, res);
}
}
cout << res << endl;
}
private:
};
int main() {
int n;
while (cin >> n) {
Solution sol;
vector<int>datasets(n,0);
for (int i = 0; i < n; i++) {
cin >> datasets[i];
}
sol.method(datasets);
}
}
字符串加法
题目描述
输入两个字符串a和b,字符串内容为二进制数字,求两个字符串相加的结果,加法计算方法以二进制方式计算,并返回对应的字符串结果。要求程序尽可能的高效。示例如下:
/**
- @param a = “1101”
- @param b = “1100”
- @return “11001”
*/
public String add(String a, String b){
}
输入描述:
输入两个字符串,如"1101", “1100”
输出描述:
“11001”
示例1
输入
1101 1100
输出
11001
思路:首先将两个字符串a,b倒序,然后保证字符串a是长度比较小的,即如果a的长度大的话,就跟b进行交换。然后我们就模拟现实中的加法,即每一位相加,如果有进位的话,就用一个变量记录下,等下一位进行相加的时候加上进位,然后保留的显然是相加结果之后对2取余,即保留各位,然后等到遍历完a字符串后,剩下的显然就只有b字符串了, 我们只需要在b字符串上加上一个进位就可以了。最后将得到的串ans在进行逆序,就得到结果了。
算法实现:
(1). 输入两个字符串a和b。
(2). 用上述的方法进行高精度加法,求出ans
(3). 输出进行加法操作之后的结果ans。
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<unordered_set>
#include<set>
#include<map>
#include<unordered_map>
#include<queue>
#include<stack>
#include<cctype>
#include<string>
#include<regex>
#include<valarray>
using namespace std;
class Solution {
public:
void methods(string a,string b){
int aLength = a.size();
int bLength = b.size();
string res;
if (aLength>bLength)swap(a,b);
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int i = 0;
int c = 0;
while (i < aLength) {
int t = a[i] - '0' + b[i] - '0' + c;
c = t / 2;
res += (t % 2 + '0');
i++;
}
while(i<bLength){
int t=b[i]-'0'+c;
c=t/2;
res+=(t%2+'0');
i++;
}
if (c) {
res += (c + '0');
}
reverse(res.begin(), res.end());
cout << res << endl;
}
};
int main() {
string a, b;
Solution sol;
while (cin >> a >>b) {
sol.methods(a,b);
}
}
方格走法
题目描述
有一个X*Y的网格,小团要在此网格上从左上角到右下角,只能走格点且只能向右或向下走。请设计一个算法,计算小团有多少种走法。给定两个正整数int x,int y,请返回小团的走法数目。
输入描述:
输入包括一行,空格隔开的两个正整数x和y,取值范围[1,10]。
输出描述:
输出一行,表示走法的数目
示例1
输入
3 2
输出
10
思路:
利用递归来解决这个问题
我们从最终点出发往前递推x-1或者y-1
当有一个坐标变成0后说明有了一条道
而均不为0时继续-1的操作
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<unordered_set>
#include<set>
#include<map>
#include<unordered_map>
#include<queue>
#include<stack>
#include<cctype>
#include<string>
#include<regex>
#include<valarray>
using namespace std;
class Solution {
public:
void backtrack(int m, int n) {
if (m == X || n == Y) {
count++;
return;
}
backtrack(m +1, n);
backtrack(m, n +1);
}
void methods(int m,int n ){
X=m;
Y=n;
backtrack(0, 0);
cout << count << endl;
}
private:
int X;
int Y;
int count = 0;
};
int main() {
int m,n;
while (cin >> m>>n) {
Solution sol;
sol.methods(m,n);
}
}