【面试】【算法】将0放到前面,非0数字放到后面,非0数字的相对次序不变。T(n)和O(n)

题目描述

给定一个随机的整数数组,含有0 和 非0的整数。

要求:将0放到数组前面,非0整数放到后面,且非0整数的相对次序不能改变。空间复杂度要求T(n),换言之不能新建辅助数组,时间复杂度要求O(n)。

例:

输入:1, 0, 2, 0, 3, 0, 0, 4, 5, 0, 6, 7

输出:0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7

前言

我同学参加cvte校招的电话面试时被问到的一题算法题,然后跟我讨论了一下。大概题意,如上面所描述。不过面试官只要求了空间复杂度为T(n),并没有对时间复杂度作出明确要求。可能就是考考思维吧。同学给我讲了题意后,我自己拿笔在草稿本上瞎比划,首先很自然想到的是有点类似于“冒泡”的操作,但显然时间复杂度为O(n^2)。

后来发现了可以有O(n)的做法。首先统计出数组中0的个数cnt,设两个指针,前指针p从下标0开始,后指针q从下标cnt开始。通过一定规则的交换(参见代码),遍历一遍数组就可以达到题目要求的结果。时间复杂度为O(2n),也就是O(n)。

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

// 时间复杂度O(2*n),也是O(n) 
void solve(int num[], int n) {
	int cnt=0; // 0的个数
	for(int i=0; i<n; i++)	{
		if(num[i]==0) {
			cnt++;
		}
	} 
	
	int p=0;	// 前指针 
	int q=cnt;	// 后指针 
	while(p<cnt) {
		
		if(num[p]==0) {
			p++;
		} else { // num[p]!=0 有两种情况 
			if(num[q]==0) {
				swap(num[p], num[q]);
				p++;
				q++;
				
			} else {
				swap(num[p], num[q]); 
				
				q++;  // num[q]已经是正确结果,所以指向下一位
				// 而num[p]是暂存了原本的num[q]的数,还不是正确结果,所以不移动指针 
			}
		}
	}
} 

// O(n^2)
void bubble(int num[], int n) {
	int flag;
	do {
		flag=0;
		for(int i=1; i<n; i++) {
			if(num[i-1]!=0 && num[i]==0) {
				flag=1;
				swap(num[i-1], num[i]);
			}
		}
	} while(flag);
	
}

int main() {
	
	int num[] = { 1, 0, 2, 0, 3, 0, 0, 4, 5, 0, 6, 7 };
	int n=12;
	
	printf("操作之前:\n");
	for(int i=0; i<n; i++)	{
		printf("%d ", num[i]);
	}
	
	// O(n) 
	solve(num, n);
	
	// O(n^2)
	//bubble(num, n);
	
	
	printf("\n操作之后:\n");
	for(int i=0; i<n; i++)	{
		printf("%d ", num[i]);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43290318/article/details/111502944