【反思与总结---4】在线OJ④

统计完全数个数、扑克牌大小

题目要求:

<1>.完全数就是所有约数之和等于自身的数
<2>.给定一个数m,找出m以内所有完全数的个数

解题思路:

<1>.先写一个判断是不是完全数的函数
<2>.再写一个循环从1循环到m,是完全数就count++
<3>.输出count

代码示例:

#include<iostream>
#include<vector>
#include<math.h>

using namespace std;

bool isPerferctNum(int num)
{
	int sum = 0;
	vector<int> v;
	
	for (int i = 1; i < num; ++i)
	{
		if ((num%i) == 0)
		{
			v.push_back(i);
		}
	}

	for (int i = 0; i < v.size(); ++i)
	{
		sum += v[i];
	}

	if (sum == num)
	{
		return true;
	}
	return false;
}

int FindPerNum(int n)
{
	int count = 0;

	for (int i = 0; i < n;++i)
	{
		if (isPerferctNum(i+1) == true)
		{
			count++;
		}
	}
	return count;
}

int main()
{
	int n;

	while (cin >> n)
	{
		cout << FindPerNum(n) << endl; 
	}

	system("pause");
	return 0;
}

题目要求:

<1>.输入两手牌,两手牌之间用“-”连接,每手牌的每张牌以空格分隔,“-”两边没有空格,如4 4 4 4-joker JOKER
<2>.输出两手牌中较大的那手,不含连接符,扑克牌顺序不变,仍以空格隔开;如果不存在比较关系则输出ERROR

基本规则:
(1)输入每手牌可能是个子,对子,顺子(连续5张),三个,炸弹(四个)和对王中的一种,不存在其他情况,
    由输入保证两手牌都是合法的,顺子已经从小到大排列;
    
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比
    较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子)
    
(3)大小规则跟大家平时了解的常见规则相同,个子,对子,三个比较牌面大小;顺子比较最小牌大小;炸弹大
    于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;
    
(4)输入的两手牌不会出现相等的情况。

答案提示:
(1)除了炸弹和对王之外,其他必须同类型比较。
(2)输入已经保证合法性,不用检查输入是否是合法的牌。
(3)输入的顺子已经经过从小到大排序,因此不用再排序了

解题思路:

<1>.各种if elseif往上堆,一条条判断…
<2>.虽说已ac,但是我写的也太菜了…等答案等答案…

感觉我多写了两个else if,算了等答案再修改…

代码示例:

#include<iostream>
#include<string>

using namespace std;

void ComPare(string& A, string& B)
{
	string s = "345678910JQKA2";

	if (A == "joker JOKER" || B == "joker JOKER")
	{
		cout << "joker JOKER" << endl;
	}
	else if (A.size() == 7 && B.size() != 7)
	{
		cout << A << endl;
	}
	else if (B.size() == 7 && A.size() != 7)
	{
		cout << B << endl;
	}
	else if ((A.size() == B.size()))
	{
		if (A == "JOKER" || B == "JOKER")
		{
			cout << "JOKER" << endl;
		}
		else if ((A == "joker"&&B != "JOKEr") || (B == "joker"&&A != "JOKER"))
		{
			cout << "joker" << endl;
		}

		if (s.find(A[0]) > s.find(B[0]))
		{
			cout << A << endl;
		}
		else
		{
			cout << B << endl;
		}
	}
	else if ((A.size() == 2 && B.size() == 1) ||
		(B.size() == 2 && A.size() == 1) ||
		(A.size() == 5 && B.size() == 3) ||
		(B.size() == 5 && A.size() == 3))
	{
		if (s.find(A[0]) > s.find(B[0]))
		{
			cout << A << endl;
		}
		else
		{
			cout << B << endl;
		}
	}
	else if (A.size() > 7 && B.size() > 7)
	{
		if (s.find(A[0]) > s.find(B[0]))
		{
			cout << A << endl;
		}
		else
		{
			cout << B << endl;
		}
	}
	else
	{
		cout << "ERROR" << endl;
	}
}

int main()
{
	string s;

	while (getline(cin, s))
	{
		int position = s.find('-');
		string A = s.substr(0, position);
		string B = s.substr(position + 1);

		ComPare(A, B);
	}

	system("pause");
	return 0;
}

反思:

在gcc编译器下,对于 int i = 3; printf("%d %d", ++i, ++i),运行输出为:5 5

main()
{     
    char str[]="Geneius";
    print (str);
} 

print(char *s)
{
	  if(*s)
	  {
	       print(++s);
	       printf("%c",*s); 
 	  }
}

下面代码的输出是suiene

考察递归, * s指向G的时候调用print,++s,s指向e…最终*s为空,递归结束,相当于从右往左打印到e

#include <iostream>
using namespace std;
int main(void)
{
	const int a = 10;
	int * p = (int *)(&a);
	*p = 20;
	cout<<"a = "<<a<<", *p = "<<*p<<endl;
	return 0;
}

编译器优化的结果,编译器在处理 const int a = 10;这句时 没有为a分配内存赋值

而是在加入了符号表,后续引用a时有些类似#define a 10这样处理,所以出现了同地址两个值

Widget f(Widget u)
{
	Widget v(u);
	Widget w=v;
	return w;
}

main()
{
	Widget x;
	Widget y=f(f(x));
}

y=f(f(x)) 有两层 f() ,为了说明过程,把里面的一层标明为 f_1 ,外面一层标明为 f_2

则 7 次调用分别是:

x  ->  f_1 的 u

f_1 的 u  ->  f_1 的 v

f_1 的 v  ->  f_1 的 w

f_1 的 w  ->  f_2 的 u

f_2 的 u  ->  f_2 的 v

f_2 的 v  ->  f_2 的 w

f_2 的 w  ->  y
struct Test
{
	Test( int ) {}
	Test() {}
	void fun() {}
};

void main( void )
{
	Test a(1);
	a.fun();
	Test b();
	b.fun();
}

Test b();—>调用一个名为b的函数,返回值类型为Test,并不是创建了一个Test类型的对象b

#include<iostream>
using namespace std;

class Base
{
public:
	virtual int foo(int x)
	{
		return x * 10;
	}

	int foo(char x[14])
	{
		return sizeof(x)+10;
	}
};

class Derived : public Base
{
	int foo(int x)
	{
		return x * 20;
	}

	virtual int foo(char x[10])
	{
		return sizeof(x)+20;
	}
};

int main()
{
	Derived stDerived;
	Base *pstBase = &stDerived;

	char x[10];
	printf("%d\n", pstBase->foo(100) + pstBase->foo(x));

	return 0;
}

pstBase->foo(100)调用基类的foo但是同名隐藏,所以调用的是派生类的foo,结果为2000

pstBase->foo(x),调用基类的foo,指针在32位操作系统下大小为4,所以输出2014

virtual int foo(int x),基类的虚函数

int foo(char x[14]),基类虚函数重载

virtual int foo(char x[10]),派生类自己定义的虚函数,只在派生类的子类中有用,干扰选项

<1>.牌数相同时,只需要比较第一张牌,只需要做到10把其他数字大就可以
<2>.王炸已经单独讨论了,所以牌数不同谁是炸弹输出谁
<3>.不满足比较条件的直接输出ERROR

如果做到逻辑清晰,也不是很难…

正确代码示例:

#include<iostream>
#include<algorithm>
#include<string>

using namespace std;

string ComPareCard(string S)
{
	if (S.find("joker JOKER") != string::npos)
	{
		return "joker JOKER";
	}
	else
	{
		int pos = S.find('-');
		string A = S.substr(0, pos);
		string B = S.substr(pos + 1);

		//获取空格的个数,牌数为空格数+1
		int C1 = count(A.begin(), A.end(), ' ');
		int C2 = count(B.begin(), B.end(), ' ');
		
		string A1 = A.substr(0, ' ');
		string B1 = B.substr(0, ' ');

		string s = "345678910JQKA2jokerJOKER";

		if (C1 == C2)
		{
			cout << (s.find(C1) > s.find(C2) ? C1 : C2) << endl;
		}
		else
		{
			if (C1 == 3)
			{
				return A1;
			}
			else if (C2 == 3)
			{
				return B1;
			}
			else
			{
				return "ERROR";
			}
		}
	}
}

int main()
{
	string S;

	while (getline(cin, S))
	{
		cout << ComPareCard(S) << endl;
	}

	system("pause");
	return 0;
}

杨辉三角变形、超长整数加法

题目要求:

<1>.求第N行,第一个偶数出现的位置
<2>.如果没有偶数,则输出-1

解题思路:

<1>.我一开始以为是编程题…没做出来…
<2>.结果看到别人答案居然是找规律??

这样是不是不太合适…应该还是用正常的方法…等答案…

代码示例:

#include<iostream>

using namespace std;

int main()
{
	int n;

	while (cin >> n)
	{
		if (n <= 2)
		{
			cout << -1 << endl;
		}
		else if (n % 2 != 0)
		{
			cout << 2 << endl;
		}
		else if (n % 4 == 0)
		{
			cout << 3 << endl;
		}
		else
		{
			cout << 4 << endl;
		}
	}

	return 0;
}

题目要求:

<1>.输入两个字符串数字
<2>.输出相加后的结果,string型

解题思路:

<1>.针对长短不一的对齐问题,把短的那个补到一样长,使用resize
<2>.从末尾开始相加,flag作为进位标志
<3>.相加的时候-‘0’,把相加好的结果转为char型存入C
<4>.每一位相加的结果%10就是进位的值,比如21,进位就是2
<5>.最后把C逆置,输出C

代码示例:

#include<iostream>
#include<algorithm>
#include<string>

using namespace std;

string AddLongInt(string A, string B)
{
	string C;

	if (A.size() > B.size())
	{
		int n = A.size() - B.size();

		while (n)
		{
			B.insert(B.begin(), '0');
			n--;
		}
	}
	else
	{
		int n = B.size() - A.size();

		while (n)
		{
			A.insert(A.begin(), '0');
			n--;
		}
	}

	int flag = 0;

	for (int i = A.size() - 1; i >= 0; --i)
	{
		int temp = (A[i] - '0') + (B[i] - '0') + flag;
		C += char((temp % 10) + '0');
		flag = temp / 10;
	}

	if (flag == 1)
	{
		C += '1';
	}
	//for (auto& e : C)
	//{
	//	e += '0';
	//}

	reverse(C.begin(),C.end());

	return C;
}

int main()
{
	string A;
	string B;

	while (cin >> A >> B)
	{
		cout << AddLongInt(A, B) << endl;
	}

	system("pause");
	return 0;
}

反思:

<1>.正确做法就是先把杨辉三角弄出来
<2>.按照题目意思,可以发现第n行有2n - 1个元素,第i,j元素等于上一行第j - 2,j - 1,j三列元素之和
<3>.每一行的第一列和最后一列都为1,如果是第二列,则只是两个元素之和
<4>.然后慢慢找,找到就输出

正确代码示例:

#include<iostream>
#include<vector>

using namespace std;

int main()
{
	int n, m;

	while (cin >> n)
	{
		m = 2 * n - 1;

		vector<vector<int>> v(n, vector<int>(m, 0));

		v[0][0] = 1;

		for (int i = 1; i < n; ++i)
		{
			//第一列和最后一列都是1
			v[i][0] = v[i][2 * i] = 1;

			for (int j = 1; j < 2 * i; ++j)
			{
				//第二列,只是两个元素的和
				if (j == 1)
				{
					v[i][j] = v[i - 1][j - 1] + v[i - 1][j];
				}
				else
				{
					//第i,j元素等于上一行第j-2,j-1,j三列元素之和
					v[i][j] = v[i - 1][j - 2] + v[i - 1][j - 1] + v[i - 1][j];
				}
			}
		}

		int k;

		for (k = 0; k < m; ++k)
		{
			if (v[n - 1][k] % 2 == 0 && v[n - 1][k] != 0)
			{
				cout << k + 1 << endl;
				break;
			}
		}

		if (k == m)
		{
			cout << -1 << endl;
		}
	}

	return 0;
}

统计兔子、字符串通配符

题目要求:

<1>.一只兔子,出生之后每三个月生一只兔子,小兔子长到三个月又生一只小兔子,假设兔子都不死
<2>.输入一个int型表示月份
<3>.输出兔子总数int型

解题思路:

斐波那契数列的应用

代码示例:

#include<iostream>

using namespace std;

int GetCount(int n)
{
    if(n==1||n==2)
    {
        return 1;
    }
    else
    {
        return GetCount(n-1)+GetCount(n-2);
    }
}

int main()
{
    int n;
    
    while(cin>>n)
    {
        cout<<GetCount(n)<<endl;
    }
    
    return 0;
}

题目要求:

<1>.输入一个带通配符的字符串在输入一个需要匹配的字符串
<2>.输出匹配结果

解题思路:

<1>.牛客网的测试用例好像不全,我第一次ac的代码我自测都有问题…
<2>.之后改了一下性能变差了,但是应该是都可以匹配了…
<3>.就是分情况判断…代码很垃圾…等答案…学…

代码示例:

#include<iostream>
#include<string>

using namespace std;

bool stringMatch(string A, string B)
{
	//te?t*.*
	//txt12.xls
	int i = 0;

	for (i; i < A.size(); ++i)
	{
		for (int j = 0; j < B.size(); ++j)
		{
			if (A[i] == B[j])
			{
				i++;
				continue;
			}
			else if (A[i] == '?')
			{
				i++;
				continue;
			}
            //a.*
            //a.abc
			else if (A[i] == '*'&&i == A.size() - 1)
			{
				break;
			}
			// *.a
			// abc.a
			else if (A[i] == '*'&&A[i + 1] == '.')
			{
				i = A.find('.') + 1;
				j = B.find('.');
				continue;
			}
			else if (A[i] == '*')
			{
				i++;
				continue;
			}
			else
			{
				return false;
				break;
			}
		}
	}

	if (i >= A.size())
	{
		return true;
	}
	return false;
}

int main()
{
	string A;
	string B;

	while (cin >> A >> B)
	{
		if (stringMatch(A, B) == true)
		{
			cout << "true" << endl;
		}
		else
		{
			cout << "false" << endl;
		}
	}

	system("pause");
	return 0;
}

汽水瓶、查找两个字符串重复最大字串

题目要求:

<1>.商店规定三个空汽水瓶可以换一瓶汽水,可以向老板借
<2>.输入文件最多包含10组测试数据,每个数据占一行,表示小张手上的空汽水瓶数
<3>.n=0表示输入结束,你的程序不应当处理这一行
<4>.对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数.如果一瓶也喝不到,输出0

解题思路:

<1>.对于大佬的数学分析可得,喝的汽水数量等于瓶数/2,这种思路,太难了…
<2>.使用递归求解,n == 1喝不到,n == 2只能喝一瓶
<3>.n>2的时候,return GetDrink(n-2)+1;

代码示例:

#include<iostream>

using namespace std;

int GetDrink(int n)
{
    if(n==1)
    {
        return 0;
    }
    else if(n==2)
    {
        return 1;
    }
    else
    {
        return GetDrink(n-2)+1;
    }
}

int main()
{
    int n;

    while(cin>>n)
    {
        if(n==0)
        {
            break;
        }
        else
        {
            cout<<GetDrink(n)<<endl;
        }
    }

    return 0;
}

题目要求:

<1>.查找两个字符串a,b中的最长公共子串.若有多个,输出在较短串中最先出现的那个
<2>.输入两个字符串
<3>.返回重复出现的字符

解题思路:

<1>.暴力破解…从第一个字符开始逐个字符增加取子串,如果在字符串B中出现就保存起来
<2>.取子串一定要从头开始逐个增加取,如果从头开始取最大的逐个递减,找到的子串可能不是最先出现的
<3>.find的返回值是int类型,是字符串的下标,如果返回npos代表没找到
<4>.出现长度比之前保存的大的就替换
<5>.最后输出找到的子串

代码示例:

#include<iostream>
#include<string>

using namespace std;

string FindSameString(string A, string B)
{
	if (A.size() > B.size())
	{
		swap(A, B);
	}

	string s;

	//for (int i = A.size(); i > 0; --i)
	for (int i = 0; i < A.size(); ++i)
	{
		//for (int j = 0; j < A.size(); ++j)
		for(int j = i; j<A.size(); ++j)
		{
			string tmp = A.substr(i, j - i + 1);

			//find返回的是字符串的下标,没找到返回npos

			if (B.find(tmp) == string::npos)
			{
				continue;
			}
			else if (tmp.size()>s.size())
			{
				s = tmp;
			}
		}
	}
	return s;
}

int main()
{
	string A;
	string B;

	while (cin >> A >> B)
	{
		cout << FindSameString(A, B) << endl;
	}

	system("pause");
	return 0;
}

字符串反转、公共字串计算

题目要求:

<1>.输入N个字符
<2>.输出反转过后的字符

解题思路:

string中提供的reverse方法

代码示例:

#include<iostream>
#include<algorithm>
#include<string>

using namespace std;

int main()
{
    string A;

    while(cin>>A)
    {
        reverse(A.begin(),A.end());
        cout<<A<<endl;
    }

    return 0;
}

题目要求:

<1>.计算两个字符串的最大公共字串的长度,字符不区分大小写
<2>.输入两个字符串
<3>.输出一个整数

解题思路:

<1>.前面做过查找最大公共字串,这个题就是输出的不是公共字串,输出它的size
<2>.暴力破解,从最大的递减查,是公共字串就保存起来,遇到更大的就替换
<3>.字符不区分大小写,所以全部转成大写

代码示例:

#include<iostream>
#include<cctype>
#include<string>
#include<algorithm>

using namespace std;

int GetCommonStrLengrh(string A,string B)
{
    transform(A.begin(),A,end(),A.begin(),towupper);
    transform(B.begin(),B,end(),B.begin(),towupper);

    string A1=A.size()<B.size()?A:B;
    string B1=A.size()<B.size()?B:A;

    string C;

    string tmp;

    for(int i=0;i<A1.size();++i)
    {
        for(j=A1.size()-1;j>=0;--j)
        {
            tmp=A1.substr(i,j);

            if(B1.find(tmp)!=string::npos)
            {
                if(tmp.size()>C.size())
                {
                    C=tmp;
                }
            }
        }
    }

    return C.size();
}

int main()
{
    string A;
    string B;

    while(cin>>A>>B)
    {
        cout<<GetCommonStrLengrh(A,B)<<endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值