算法,不改变正负数之间相对顺序重新排列数组.时间O(N),空间O(1)

大概思路:
1,遍历数组,找到最小值,最大值,以及负数元素个数,然后设 s = 最小值绝对值,m = 最大值 + 1,k = 负数元素个数 - 1。

2,遍历数组,改变每个元素,设该元素为a, 改变后为 c = a+s + (m+s)*n, 其中,n为该元素在按照题目要求排序后的位置,其实不难得到,遍历过程中分别用两个变量保存当前正负元素的排序号,如果当前元素是负数,则第一个变量+1然后付值给n,如果是正数,则第二个变量+1然后付值给n,注意,第一个变量从0开始计数,第二个从k开始计数。

3,再次遍历数组,设每个元素为c,则c对(m+s)取余数后得到b,由于b= a+s => a = b-s,然后 (c -b)/(m+s) 得到n,也就是该元素的排序号,用此排序号进行占位排序,一个替一个一直到最大号。


简单的说如果把数组先变成正数,
A ={-1,8,-2,-3,2,7} , 最大元素 8 设m=8+1=9, -3最小设s=3,都加3=> {2,11,1,0,5,10}=B。

然后是用最大元素11加上1=12,即m+s=9+3=12 作为参数用于改变数组B每个元素,C={2+12*1, 11+12*4(也就是初始数组元素8到最后应该排在第4位), 1+12*2, 0+12*3, 5*12*5, 10*12*6}
初始数组A最大元素8=>m=8+1=9,也就是说m+s=9+3=12大于任何一个数组B中的元素,那么通过构造C中元素c=a+s+(m+s)*n我们不但能够存储原有A中元素a,还可以存储排序后的排号n.
原理等同于那个把整数变成浮点数的方法,但是我这里通过计算还原原来的元素以及排序号,c%(m+s)得到a+s,a可以还原,(c-a-s)/(m+s)得到排序号。

代码如下:

#include <limits>
#include <iostream>


using namespace std;

int main(int argc, char **argv)
{
	const size_t size = 6;
	int A[size] = {-3,1,8,-2,1,2};
	
	//first step, find min, max 
	
	int min = numeric_limits<int>::max();
	int max = numeric_limits<int>::min();
	//and number of elements which is less than 0
	//later used as unsigned elements new position
	size_t unsignedCnt = 0; 
	for(size_t i = 0; i < size; ++i)
	{
		if(A[i] < min)
			min = A[i];
		if(A[i] > max)
			max = A[i];
		if(A[i] < 0)
			++unsignedCnt;
	}
	++max;
	if(min < 0)
		min = -min;
	
	//signed elements first position
	size_t signedCnt = 0;	
	
	//new position index
	size_t cnt = 0;
	for(size_t i = 0; i < size; ++i)
	{
		//update element to make them greater than 0
		//and include a final position in 
		
		if(A[i] < 0)		
			cnt = ++signedCnt;			
		else		
			cnt = ++unsignedCnt;
		
		
		//update element
		//cnt starts from 1
		A[i] = A[i] + min + (min + max) * cnt;
		}
	
	
	//in-place key index sorting
	for(size_t i = 0; i < size; ++i)
	{
		//if the element already put in right position continue
		if(A[i] <= max) continue;
		else
		{
			int temp = 0;			
			int prev = A[i];
			size_t id = 0;			
						
			do{				
				temp = prev % (max + min);
				id = (prev - temp)/(min + max) - 1;
				prev = A[id];				
				A[id] = temp - min;								
			}while(id != i);			
			
		}
			
	}

	for(size_t i = 0; i < size; ++i)
	{
		cout << A[i]<<endl;
	}		
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用双指针的方法来实现。定义两个指针i和j,初始时i=0,j=1。从头开始遍历顺序表,如果a[i]和a[j]相等,则j++;否则将a[j]赋值给a[i+1],i++,j++。最后将i+1赋值给表长即可。 以下是代码实现: void removeDuplicates(int a[], int n) { if (n <= 1) return; int i = 0, j = 1; while (j < n) { if (a[i] == a[j]) { j++; } else { a[i+1] = a[j]; i++; j++; } } n = i + 1; } ### 回答2: 题目要求在一个非递减的顺序表中删除所有值相等的多余数,且时间复杂度为O(n),空间复杂度为O(1)。 为了满足时间复杂度为O(n),我们需要遍历顺序表一次,找出所有多余的数,并删除它们。 具体实现步骤如下: 1. 定义一个变量count,用来记录当前不重复的元素的个数,初始化为1。 2. 遍历顺序表,从第二个元素开始,依次比较当前元素与前一个元素是否相等。 3. 如果当前元素与前一个元素不相等,则将该元素移动到count位置,count加1。 4. 如果当前元素与前一个元素相等,则继续往后查找,直到找到不相等的元素为止。 5. 遍历完成后,count即为新的顺序表的长度,将其后面的元素全部删除。 示例代码如下: ```c void removeDuplicates(int* nums, int numsSize) { if (numsSize == 0) { return; } int count = 1; for (int i = 1; i < numsSize; i++) { if (nums[i] != nums[i - 1]) { nums[count] = nums[i]; count += 1; } } // 删除多余的元素 for (int i = count; i < numsSize; i++) { nums[i] = 0; // 这里只是将多余的元素置为0,实际情况可能需要进行内存的释放操作 } } ``` 以上代码实现了在一个非递减的顺序表中删除所有值相等的多余数的需求,算法时间复杂度为O(n),空间复杂度为O(1)。 ### 回答3: 使用C语言可以通过双指针法在一个非递减的顺序表中删除所有值相等的多余数,满足时间复杂度O(n)和空间复杂度O(1)的要求。 具体步骤如下: 1. 定义两个指针i和j,初始时都指向顺序表的第一个元素。 2. 从第二个元素开始,依次与前一个元素进行比较。 3. 若当前元素与前一个元素不相等,则将i+1,将当前元素赋值给i所指向的位置。 4. 若当前元素与前一个元素相等,则继续往后遍历找到第一个与当前元素不相等的元素,并将其赋值给i+1的位置。然后将i+1。 5. 重复步骤2-4直到遍历完整个顺序表。 6. 最后将指针i的位置作为顺序表的新长度,将其后的元素全部删除。 以下是一个示例代码实现: ```c #include<stdio.h> void removeDuplicates(int arr[], int n) { int i = 0, j = 1; // 定义双指针i和j while (j < n) { if (arr[j] != arr[i]) { // 当前元素与前一个元素不相等 arr[++i] = arr[j++]; // 将当前元素赋值给i所指向的位置,然后i和j都加1 } else { // 当前元素与前一个元素相等 while (j < n && arr[j] == arr[i]) { // 找到第一个与当前元素不相等的元素 j++; } if (j < n) { // 若还有剩余元素,则将其赋值给i+1的位置 arr[++i] = arr[j++]; } } } // 将指针i的位置作为顺序表的新长度,将其后的元素全部删除 n = i + 1; } int main() { int arr[] = {1, 2, 2, 3, 3, 3, 4}; int n = sizeof(arr) / sizeof(arr[0]); removeDuplicates(arr, n); printf("顺序表删除重复元素后的结果为:"); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } ``` 执行以上代码,输出结果为: ``` 顺序表删除重复元素后的结果为:1 2 3 4 ``` 通过以上方法,我们可以在一个非递减的顺序表中删除所有值相等的多余数,并且满足时间复杂度O(n)和空间复杂度O(1)的要求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值