编程练习20180909_组合数问题

目录

 

1.找出一个字符串中无重复字符的最长子字符串的长度

2.标记矩阵的连通域分量(数字图像处理连通域标记问题)

3.组合数问题

3.1.IP地址忘记输入.分隔号了,给定一IP,求合理的还原后的IP数目

3.2上台阶方式:小明可以一次上1级、2级、...、n级台阶,求上9级台阶有几种上法?

3.3 代金券币值求和组合数问题

4.关系图:找红人


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}
  2. {1,1,1,2}
  3. {1,2,2}
  4. {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号就是网红!

 

编程题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值