目录
3.1.IP地址忘记输入.分隔号了,给定一IP,求合理的还原后的IP数目
3.2上台阶方式:小明可以一次上1级、2级、...、n级台阶,求上9级台阶有几种上法?
1.找出一个字符串中无重复字符的最长子字符串的长度
如"abcabcbb"的最长无重复的子串有:"abc","bca","acb",最长的无重复字符的字串的长度为3;
abca
abcb
abcc
思路:
如string str="abcb"
建立一个存储找到的所以没有重复字母的子串的向量:
vector<int> MaxSubStrVec ;//将每一次找到的无重复字母的字串的长度都push_back进去,最后输出起最大值。或者直接用个优先队列,大顶堆来保存:priority_queue;
建立一个标记向量,标记26个字母在字串中的出现与否的状态:
vector<int> Flags(26,0);//初始全为0
再建立一个子串字符(字母)出现在主串中的位置(下标)向量:
vector<int> Loc(26,0);//初始全为0
i=0;str[0]=a;if(Flags[str[0]-'a']==0){Flags[str[0]-'a']=1;maxLength++; Loc[str[i]-'a']=i}
i=0;str[1]=b;if(Flags[str[1]-'a']==0){Flags[str[1]-'a']=1;maxLength++;Loc[str[i]-'a']=i}
i=2;str[2]=c;if(Flags[str[2]-'a']==0){Flags[str[2]-'a']=1;maxLength++;Loc[str[i]-'a']=i}
i=3;str[3]=b;Flags[str[3]-'a']!=0,,则不在纳入子串,请将下标i回溯道前面子串重复的字符的下一个位置2,Flags清0,Loc清0
对于abcd这样主串就没有重复字符的,也要将最大值累加上去。
2.标记矩阵的连通域分量(数字图像处理连通域标记问题)
5
1 0 0 1 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
3
1 0 0 2 2
1 0 0 2 2
0 0 3 0 0
0 0 3 0 0
0 0 3 0 0
如下面的矩阵,有三个连通域(连通只四邻域连通,即上下左右的值相同的判为连通)
1 0 0 1 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
有三个连通域,标记如下:
1 0 0 2 2
1 0 0 2 2
0 0 3 0 0
0 0 3 0 0
0 0 3 0 0
思路:利用栈,区域生长,直到长到无法扩充该区域的时候,开始退栈!
实现代码:
版本1:递归版本:
typedef struct Point{
int x, y;
}Point;
void MarkMatrix(int i, int j, vector<vector<int>>& Matrix, vector<vector<int>>& Visited, vector<vector<int>>& Flags, int DepartmentCount)
{
if (Matrix[i][j] == 1 && Visited[i][j] == 0 )
{
Visited[i][j] = 1;
if (i - 1 >= 0)
{
MarkMatrix(i-1, j, Matrix, Visited, Flags, DepartmentCount);
}
if (i + 1 < Matrix.size())
{
MarkMatrix(i + 1, j, Matrix, Visited, Flags, DepartmentCount);
}
if (j - 1 >= 0)
{
MarkMatrix(i, j-1, Matrix, Visited, Flags, DepartmentCount);
}
if (j + 1 <Matrix.size())
{
MarkMatrix(i, j + 1, Matrix, Visited, Flags, DepartmentCount);
}
Flags[i][j] = DepartmentCount;
}
}
int HowManyDepatment(vector<vector<int>>& Matrix, vector<vector<int>>& Visited, vector<vector<int>>& Flags)
{
int M = Matrix.size();
int DepartmentCount = 0;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < M; j++)
{
if (Matrix[i][j] == 1 && Visited[i][j] == 0)
{
DepartmentCount++;
MarkMatrix(i, j, Matrix, Visited, Flags, DepartmentCount);
}
}
}
return DepartmentCount;
}
版本2:利用栈写出非递归的循环版本:
typedef struct Point{
int x, y;
}Point;
void StackPush(stack<Point>& S, int i, int j, vector<vector<int>>& Matrix, vector<vector<int>>& Visited)
{
if (Matrix[i][j] == 1 && Visited[i][j] == 0)
{//只有满足条件的点才push进栈
Point p = { i, j };
S.push(p);
}
}
int HowManyDepatmentLoopStack(vector<vector<int>>& Matrix, vector<vector<int>>& Visited, vector<vector<int>>& Flags)
{
int M = Matrix.size();
int DepartmentCount = 1;
stack<Point> CCStack;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < M; j++)
{
if (Matrix[i][j] == 1 && Visited[i][j] == 0)
{/*遇到一个标记为1且没有访问过的点,就将该点入栈*/
StackPush(CCStack, i, j,Matrix,Visited);
while (!CCStack.empty())
{//栈不空,就取栈顶的点,访问之,标记之,并且弹出之,并且检测栈顶点的上下左右四个邻域点,若邻域点满足条件就要将该邻域点压入栈里去!
Point p = CCStack.top();
CCStack.pop();
Visited[p.x][p.y] = 1;
Flags[p.x][p.y] = DepartmentCount;
if (p.x - 1 >= 0)
{
StackPush(CCStack, p.x - 1, p.y, Matrix, Visited);
}
if (p.x + 1 < Matrix.size())
{
StackPush(CCStack, p.x + 1, p.y, Matrix, Visited);
}
if (p.y - 1 >= 0)
{
StackPush(CCStack, p.x, p.y - 1, Matrix, Visited);
}
if (p.y + 1 <Matrix.size())
{
StackPush(CCStack, p.x, p.y + 1, Matrix, Visited);
}
}
DepartmentCount++;//因为方便标记的问题,DepartmentCount的初值为1,栈退完的时候DepartmentCount=DepartmentCount+1;
}
}
}
return DepartmentCount-1;//因为从1标起,所以最后实际的连通区域数量是DepartmentCount-1
}
版本3:逻辑bug版本,考虑不到位,举个特例即可验证!
int HowManyDepartmentBugEditiom(vector<vector<int>>& Matrix)//逻辑bug版本!只考虑了左和上方的情况,存在逻辑漏洞,可举反例测试之!
{
int count = 0;
int M = Matrix.size();
for (int i = 0; i < M; i++)
{
for (int j = 0; j < M; j++)
{
bool flag1 = false;
bool flag2 = false;
if (Matrix[i][j] == 1)
{
if (i - 1 >= 0)
{
if (Matrix[i - 1][j] == 1)
{
flag1 = true;
}
else
{
flag1 = false;
}
}
if (j - 1 >= 0)
{
if (Matrix[i][j - 1] == 1)
{
flag2 = true;
}
else
{
flag2 = false;
}
}
if (!flag1&&!flag2)
{
count++;
}
}
}
}
return count;
}
测试代码:
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
int main(int argc, char* argv[])
{
int M;
cin >> M;
vector<vector<int>> Matrix, Visited, Flags;
int flag;
for (int i = 0; i < M; i++)
{
vector<int> matrixRow,visitedRow,flagsRow;
for (int j = 0; j < M; j++)
{
cin >> flag;
matrixRow.push_back(flag);
visitedRow.push_back(0);
flagsRow.push_back(0);
}
Matrix.push_back(matrixRow);
Visited.push_back(visitedRow);
Flags.push_back(flagsRow);
}
//cout << HowManyDepatment(Matrix, Visited, Flags);
cout << HowManyDepatmentLoopStack(Matrix, Visited, Flags);
cout << endl;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < M; j++)
{
cout << Flags[i][j] << " ";
}
cout << endl;
}
cout << endl;
//cout << HowManyDepartmentBugEditiom(Matrix);
system("pause");
return 0;
}
/*
5
1 0 0 1 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
5
1 0 0 1 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
3
1 0 0 2 2
1 0 0 2 2
0 0 3 0 0
0 0 3 0 0
0 0 3 0 0
请按任意键继续. . .
测试HowManyDepartmentBugEditiom()
1 0 0 1 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
这个矩阵比较特殊
换成下面这个矩阵就发现出问题了:
5
1 0 0 0 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
5
1 0 0 0 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
4请按任意键继续. . .(本应该只有3类,结果却是4类,
就是对第二行第四列的那个1的处理不对!检测到该点时,
只考察了其左和上,没没考察有和下,有bug!
HowManyDepatmentLoopStack()测试:
5
1 0 0 0 1
1 0 0 1 1
0 0 1 0 0
0 0 1 0 0
0 0 1 0 0
3
1 0 0 0 2
1 0 0 2 2
0 0 3 0 0
0 0 3 0 0
0 0 3 0 0
请按任意键继续. . .
*/
3.组合数问题
3.1.IP地址忘记输入.分隔号了,给定一IP,求合理的还原后的IP数目
如本来是10.0.0.1的IP
今是10001
还原出所有可能的原始IP,输出所有可能的原始IP数量
8888就只能还原为8.8.8.8
255255255也只能还原为255.255.255.255
3.2上台阶方式:小明可以一次上1级、2级、...、n级台阶,求上9级台阶有几种上法?
小明可以一次上1级、2级、...、n级台阶,求上9级台阶有几种上法?
3.3 代金券币值求和组合数问题
编程题2:
从A地到B地的高速路,中间有N个收费站,每到一个收费站需求支付相应路程的代金券
,有M种代金券,价值各不相同,代金券数量无限
例如:有两个收费站直接的距离是26,先有两种代金券:价值为2的和价值为3的,代金券量无限。
问可有多少中缴纳代金券的方式:,就问有多种组合方式!
比如有一种是:8*3+1*2=26,即8张价值3的和一张价值2的
比如还可以这样组合:6*3+4*2=26
...
求出出所有的组合情况。
int waysToDistination(int distance,int couponTypes,int couponValues[],int tolls,int tollDistances[]){}
distance为A到B的距离
couponTypes为代金券的种类数
couponValues[] 为代金券价值数组
tolls :A->B之间的收费站数
tollDistances[] 各个收费站距离A的距离
问从A->B有几种支付代金券的方式,求代金券的支付组合数!
如:
distance=10
couponTypes=4
couponValues[]={1,2,5,10}
tolls=3
tollDistances[]={0,5,10}
第一个收费站就在起点A,不需要支付代金券,也就是支付方式为1中,支付0代金券
第一个收费站到第二个收费站之间的距离是5,
通过{1,2,5,10}4中代金券,得到5的组合方式有一下几种:
- {1,1,1,1,1}
- {1,1,1,2}
- {1,2,2}
- {5}
共四种组合方式
同理第二个收费站到第三个收费站之间的距离为5,也是得到上面4中代金券的组合方式:
则从A->B 支付代金券的总的方式为1*4*4=16种!
要求实现函数:
int waysToDistination(int distance,int couponTypes,int couponValues[],int tolls,int tollDistances[]){}
返回支付代金券的组合数。
测试用例1:
输入:
10
4,[1,2,5,10]
3, [0,5,10]
输出:
16
测试用例2:
输入:
12
1,[2]
6,[0,2,4,6,8,10]
输出:
1
4.关系图:找红人
用户数N
有M个关系对(A,B):表示A关注了B
关注具有传递性:A关注了B,B关注了C,我们认为A间接也关注了C
如果一个用户被N个用户直接或间接关注,那么认为该用户是网红,
求网红的个数?
输入:
3
3
1 2 2 1 2 3
N=3
M=3
(1,2) (2,1) (2,3)
1->2
2->1
2->3
(有环的真是奇葩!)
这样解释:1和2互粉,那么认为1和2都有两个粉丝,自己是自己的粉丝
1有一个关注者
1->2->3
2->3
那么3就有3个粉丝,3号就是网红!
编程题