我是靠谱客的博主 大胆玫瑰,最近开发中收集的这篇文章主要介绍数组右移K位的思考,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        和朋友聊天,偶然聊到了数组右移的算法,不禁想起了某个大牛的三次翻转法,绝对是个经典的算法.正好今天没事,就静下心想想,还有什么更好的算法吗?

        首先能想到的就是每次右移一个,需要右移几个就执行几次就好了,假设数组长度为N,右移数为K,则时间复杂度O(N*K),但这种方法好理解,一看就明白!

 相关的算法也简单:

void LoopMove(int arr[], int count, int k)
{
	//空间O(1),时间(K*N)
	int i, j,t;
	for(i=0;i<k;i++)
	{
		t = arr[count - 1];
		for (j = count - 1; j > 0; j--)
		{
			arr[j] = arr[j - 1];
		}
		arr[0] = t;
	}
}

        然后就是大神级别的三次翻转法,将前面N-K个元素翻转,后面的K个元素翻转,最终整体翻转,时间复杂度O(N),空间复杂度O(1),确实牛!

实现代码也简单:

void Reverse(int arr[], int count)
{
	int i = 0;
	int j = count - 1;
	int t;
	while (i < j)
	{
		t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
		i++;
		j--;
	}
}

void ThreeReverse(int arr[], int count, int k)
{
	//空间O(1),时间O(N)
	Reverse(arr, count - k);
	Reverse(&arr[count - k ], k);
	Reverse(arr, count);
}

 Reverse函数完成翻转,ThreeReverse函数设置完成3次翻转

        三次翻转确实很不错了,能不能在优化一下?我想时间复杂度已经是O(N)了,不好弄,空间复杂度也O(1),也不好弄,能不能另辟蹊径?

        俗话说,最直接的也许就是最好的,基于这种想法,尝试了下面的一个算法,暂时称之为空位算法吧.思想很简单,很直接,上图:

 就是先把1存起来,7就可以放到1的未知,然后7的未知变为空位,就可以把4移到7的未知,依次下去,直到需要将最开始1需要安置时就结束了,然后把1安置好.

算法实现如下:

void HoveringPoint(int arr[], int count, int k)
{
	//满足了空间O(1),时间O(N)
	k = k % count;
	int t = arr[0];
	int c = 0,n;
	while(n=(c+count-k)%count)
	{
		arr[c] = arr[n];
		c = n;
	}
	arr[c] = t;
}

上面的代码貌似解决了问题,但实际上有一个很大的bug,如果移动的位数和数组长度的最大公约数不为1呢?这时候就会出现只有第一个相关的数据被移动,后面的2,3....都没动啊,所以,上面的代码还需要完善一下,如下:

void HoveringPoint(int arr[], int count, int k)
{
	//满足了空间O(1),时间O(N)
	k = k % count;
	if (k == 0) {
		return;
	}
	//求最大公约数
	int m = k;	//假定最大公约数为k
	int s = count;
	while (s % m )
	{
		int tmp = m;
		m = s % m;
		s = tmp;
	}
	
	//从0到最大公约数-1进行循环,确保每个数据都被循环到
	for (int i = 0; i < m; i++)
	{
		int t = arr[i];
		int c = i, n;
		while ((n = (c + count - k) % count) !=i)
		{
			arr[c] = arr[n];
			c = n;
		}
		arr[c] = t;
	}
}

我们找到最大公约数,并对从0到最大公约数-1的每一个位置都按照上面移动的逻辑处理就好了。

最后,把整体代码贴给大家,有要测试的小伙伴可以测试下啊!

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

void print(int arr[],int count)
{
	int i;
	for (i = 0; i < count; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("n");
}


void LoopMove(int arr[], int count, int k)
{
	//空间O(1),时间(K*N)
	int i, j,t;
	for(i=0;i<k;i++)
	{
		t = arr[count - 1];
		for (j = count - 1; j > 0; j--)
		{
			arr[j] = arr[j - 1];
		}
		arr[0] = t;
	}
}

void Reverse(int arr[], int count)
{
	int i = 0;
	int j = count - 1;
	int t;
	while (i < j)
	{
		t = arr[i];
		arr[i] = arr[j];
		arr[j] = t;
		i++;
		j--;
	}
}

void ThreeReverse(int arr[], int count, int k)
{
	//空间O(1),时间O(N)
	Reverse(arr, count - k);
	Reverse(&arr[count - k ], k);
	Reverse(arr, count);
}

void HoveringPoint(int arr[], int count, int k)
{
	//满足了空间O(1),时间O(N)
	k = k % count;
	if (k == 0) {
		return;
	}
	//求最大公约数
	int m = k;	//假定最大公约数为k
	int s = count;
	while (s % m )
	{
		int tmp = m;
		m = s % m;
		s = tmp;
	}
	
	//从0到最大公约数-1进行循环,确保每个数据都被循环到
	for (int i = 0; i < m; i++)
	{
		int t = arr[i];
		int c = i, n;
		while ((n = (c + count - k) % count) !=i)
		{
			arr[c] = arr[n];
			c = n;
		}
		arr[c] = t;
	}
}

//必须满足空间O(1)
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int k = 3;
	int count = sizeof(arr) / sizeof(arr[0]);
	HoveringPoint(arr, count, k);
	print(arr, count);
	return 0;
}

最后

以上就是大胆玫瑰为你收集整理的数组右移K位的思考的全部内容,希望文章能够帮你解决数组右移K位的思考所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部