算法习题 (去掉数组重复元素 + 交换一串数组元素 )

今天在一本讲基础算法的书上看到两道比较有意思的算法的题目,自己做了一下,再和书上比较一下。书上推荐的算法的确是比大家经常想到的算法优化了不少。

1、已知整数数组a[n]中有重复的元素,试实现函数 void purge( int * a, int &n ); 该函数Post 条件为a[n] 中个元素相异。
 常规思路:对表中任一个元素a[i],令 j 从 i+1 到 n-1,将a[i]和a[j]进行比较,若相等,则从顺序表中删除该元素,然后从 j+1 到 n-1 的元素均向前移动一个位置。

 弊端: 在删除元素时引起的一连串的元素向前移动非常费时,而且在上述算法中"每发现一个和a[i]相同的元素, 就删除元素+移动数组的做法会使那些值和a[i]不同的元素重复多次移动操作。 时间度为 O(n*n)。

 改进:假设我们建一个新表,对原顺序表中每一个当前考察的数据元素,在"新表"中进行查找,如果有相同的则舍弃之,否则就插入到"新表"中。这样就省去了大量的移动操作,虽然外层循环还是 n, 时间复杂度也为 O(n*n),但操作步骤却大大减少了。而且,因为这里是“删除”操作,直接对原数组进行操作,所以那个我们假设的“新表”其实就是被操作的数组,只需要新建一个“指针”(这里为数组下标)即可。
 Code:
void purge( int *a, int & n )
{
 int k = -1;
 for( int i = 0; i<n; ++i )
 {
  int j = 0;
  while( j<=k && a[j] != a[i] )
   ++j;
  if( k==-1 || j>k )
  { ++k; a[k] = a[i]; }
 }
 n = k+1;
}

2、实现函数 void exchange( int *a, int p1, int n ) , 该函数把数组a[n] 的前 p1 个元素和 剩下的后 n-p1个元素互换位置。 比如原数组为 { 1, 2, 3, 4, 5, 6, 7 } ,执行 exchange( a, 3, 7 ) 后变为 { 4,5,6,7,1,2,3 }。
 常规思路: 把后面的最后一个数插到第一个,然后平移数组。依次到把后面元素全部放到新数组的前面。时间复杂度为 O( p1*(n-p1) ).
 改进: 为了消除平移数组的巨大消耗,考虑用倒置数组或倒置数组的一部分。导致能把后面一段整体移到前端,再对移到前端的那部分做倒置,又回复了原来的数序。所以可以通过三次倒置(1次全倒+2次部分倒)能达到目的。
 推广:同样的方法,可以让数组的任何两段互换位置。
 Code:
// 倒置从下标 p1 到 p2 的数组
void invert( int a[], int p1, int p2 )  
{
 int temp;
 for(int i =p1; i<=(p1+p2)/2; ++i )
 { temp = a[i]; a[i] = a[p2+p1-i]; a[p2+p1-i]=temp; }
}

void exchange( int a[], int p1, int n )
{
 if( p1>0 && p1<n)
 {
 int p2 = n-p1;
 invert(a, 0, n-1);
 invert(a, 0, p2-1);
 invert(a, p2, n-1);
 }
}
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值