[算法学习]发帖水王

这篇博客探讨了微软亚洲研究院的Tango项目,挑战寻找‘水王’,即发帖超过一半的用户。文章通过简化问题,提出解决数组中出现次数过半的元素的算法,并进一步讨论字符串排列、台阶跳法的斐波那契数列解决方案,以及如何在O(n)时间内调整数组奇偶顺序的问题。最后,介绍了一个寻找字符串中第一个只出现一次字符的方法。
摘要由CSDN通过智能技术生成

来自:http://blog.csdn.net/v_july_v/article/details/6890054

题目1:Tango是微软亚洲研究院的一个试验项目,如图1所示。研究院的员工和实习生们都很喜欢在Tango上面交流灌水。传说,Tango有一大“水王”,他不但喜欢发帖,还会回复其他ID发的每个帖子。坊间风闻该“水王”发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的Tango水王吗?

题目简化为:求数组中出现一半以上次数的数?

思想1:排序后,输出a[n/2];

sort(a,a+N);
return a[N/2];

思想2:出现一半以上次数的数减去其他数的总次数,结果大于0

#include<iostream>
#include<algorithm>
using namespace std;
int FindCandidate(int *arr,int n);//通过次数来找出水王
int FindCandidate2(int *arr,int n);//通过排序
int main()
{
	int n=-1;
	cin>>n;
	int *arr=new int[n];
	for(int i=0;i<n;i++)
		cin>>arr[i];
	cout<<FindCandidate2(arr,n)<<endl;
	delete[] arr;
	return 0;
}
int FindCandidate(int *arr,int n)
{
	int nTimes=0,candidate=-1;
	for(int i=0;i<n;i++)
	{
		if(nTimes==0)
		{
			candidate=arr[i];
			nTimes=1;
		}else
		{
			if(arr[i]==candidate)
				++nTimes;
			else
				--nTimes;
		}
	}
	return candidate;
}
int FindCandidate2(int *arr,int n)
{
	sort(arr,arr+n);
	return arr[n/2];
}

题目2:输入一个字符串,打印出该字符串中字符的所有排列

思想:采用递归方式。比如说abc这个字符串,可以分为a+bc的全排列,b+ac的全排列,c+ab的全排列。

#include<iostream>
#include<algorithm>
using namespace std;
void permulation(char *str,int start,int len);
int k=1;
int main()
{
	char str[256]={0};
	cin>>str;
	permulation(str,0,strlen(str));
	return 0;
}
void permulation(char *str,int start,int len)
{
	if(len<=1)
	{
		cout<<k++<<" "<<str<<endl;
		return;
	}
	for(int i=start;i<start+len;i++)
	{
		swap(str[i],str[start]);//
		permulation(str,start+1,len-1);	
		swap(str[i],str[start]);
	}

}

题目3:一个台阶总共有n 级,如果一次可以跳1 级,也可以跳2 级。求总共有多少总跳法,并分析算法的时间复杂度。

分析:

台阶数总方法数具体
111、1
2 21、1+1
2、2
3 31、1+1+1
2、1+2
3、2+1
总条数f(n)=f(n-1)+f(n-2).

为什么得出这样的式子,当面对n级台阶,第一次可以跳1级,则剩下n-1级,即f(n-1);第一次跳2级,则剩下n-2级,即f(n-2)。所以f(n)=f(n-1)+f(n-2)

其实,这就是斐波那契数列。

实现:

1.递归实现:

int fibona(int n)
{
	if(n<=0)
		return -1;
	else
	if(n==1)
		return 1;
	else
	if(n==2)
		return 2;
	else
		return fibona(n-1)+fibona(n-2);
}
缺点:当台阶数比较大时,递归层次比较深。而且存在重复计算。

2、递归方式不变,以空间换时间。在递归过程中,如果求出的某一个数的结果,不在数组中,则存入到数组中。

3、不用递归,该用迭代方式。即从f(3)->f(4)->f(5).....->f(n)

int fibona2(int n)
{
	int result1=1,result2=2,result=0;
	if(n<=0)
		return -1;
	else
		if(n==1)
			return result1;
		else
			if(n==2)
				return result2;
	for(int i=3;i<=n;i++)
	{
		result=result1+result2;
		if(i%2!=0)
			result1=result;//奇数,则将结果赋值给result1
		else
			result2=result;//偶数,则将结果赋值给result2
	}
	return result;
}

题目4:输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)

分析:这到底比之前的不改变正负数之间相对顺序重新排列数组.时间O(N),空间O(1)简单,因为没要求保证相对顺序,而且只要求时间复杂度为O(n)。

申请两指针,一个指针p指向数组头,一个指针q指向数组尾。

  • p右移,找到一个偶数
  • q左移,找一个奇数
  • p与q所指向的数互换,并且p右移一位,q左移一位
  • 循环直到p>q
#include<iostream>
#include<algorithm>
using namespace std;
int exchange(int *a,int n);
int main()
{
	int n;
	cout<<"请输入数组长度"<<endl;
	cin>>n;
	if(n<=0)
		cout<<"n应该大于0"<<endl;
	else
	{
		int *a=new int[n];
		for(int i=0;i<n;i++)
			cin>>a[i];
		exchange(a,n);
		cout<<"交换过后的数组为:"<<endl;
		for(int i=0;i<n;i++)
			cout<<a[i]<<" ";
		cout<<endl;
		delete[] a;
	}
	return 0;
}
int exchange(int *a,int n)
{
	int *p=a,*q=a+n-1;
	while(p<q)
	{
		while(*p%2!=0)//找到偶数
			++p;
		while(*q%2==0)//找到奇数
			--q;
		if(p<q)
		{
			swap(*p,*q);
			++p;
			--q;
		}else
			break;
	}
	return 0;
}

题目5:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b

思想:第一次遍历字符串,将字符出现次数,存入到hash数组中.hash数组key位字符的Ascii码,value为字符出现次数.

第二次遍历字符串,找出第一个只出现一次的字符.

#include<iostream>
using namespace std;
char findOnlyOne(char *str);
int main()
{
	char str[256]={0};
	cin>>str;
	cout<<"第一次只出现一次的字符为:"<<findOnlyOne(str)<<endl;
	return 0;
}
char findOnlyOne(char *str)
{
	int num[256];
	memset(num,0,sizeof(num));
	char *p=str;
	while(*p!='\0')
	{
		num[*p]++;
		++p;
	}
	p=str;
	while(*p!='\0')
	{
		if(num[*p]==1)
			break;
		++p;
	}
	return *p;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值