练习——杨氏矩阵、字符串左旋

前言:

前段时间学习了杨氏矩阵、字符串左旋,给大家分享下这两个用代码是如何实现的(文字+画图分析)
—————————————————————————————

一.杨氏矩阵

题目:有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵的每列从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于O(N)

分析题目:
所谓的数字矩阵其实就是一个二维数组,这个二维数组只要满足每行从左到右数字是递增的,每列从上到下的数字是递增的,简单画图表示:
在这里插入图片描述
时间复杂度小于O(N)又是什么呢?
假设这个数组有N个元素,在最坏的情况下,需要遍历N次也就是找N次才能找到这个数,这时时间复杂度为O(N);小于O(N)也就是找的次数小于N即可。

方法一:暴力求解(时间复杂度==O(N))

遍历数组的每个元素,直到找到为止,否则找不到。

int main()
{
    
    
	int arr[3][3] = {
    
     1,2,3,4,5,6,7,8,9 };
	int k = 0;
	scanf("%d", &k);
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
    
    
		for (j = 0; j < 3; j++)
		{
    
    
			if (arr[i][j] == k)
			{
    
    
				printf("找到了,下标是:%d %d",i,j);
				return 0;
			}
		}
	}
	printf("找不到\n");
	return 0;
}

这个解法效率较低

方法二:时间复杂度<O(N)

从矩阵的右上角开始找,当要找的数字大于右上角的数字时,因为右上角的数字是所在行的最大数字,所以行加1;当要找的数字小于右上角的数字时,因为右上角的数字是所在列的最小数字,所以列减1;直到找到为止。这个方法相当于每找一次就去掉了一行或者一列,效率更高。
在这里插入图片描述

int main()
{
    
    
	int arr[3][3] = {
    
     1,2,3,4,5,6,7,8,9 };
	int k = 0;
	scanf("%d", &k);
	int x = 0;
	int y = 2;
	int f = 0;
	while (x <= 2 && y >= 0)
	{
    
    
		if (arr[x][y] < k)
		{
    
    
			x++;
		}
		else if (arr[x][y] > k)
		{
    
    
			y--;
		}
		else
		{
    
    
			printf("找到了,下标是:%d %d", x, y);
			f = 1;
			break;
		}
	}
	if (f == 0)
		printf("找不到\n");
	return 0;
}

方法三:使用更巧妙的方法(时间复杂度<O(N))

用一个函数来实现找到了还是没找到,把行和列以指针的形式传参,返回值在主函数里打印结果

void test(int arr[3][3], int k, int* px, int* py)
{
    
    
	int x = 0;
	int y = *py - 1;
	while (x <= *px - 1 && y >= 0)
	{
    
    
		if (arr[x][y] < k)
		{
    
    
			x++;
		}
		else if (arr[x][y] > k)
		{
    
    
			y--;
		}
		else
		{
    
    
			*px = x;
			*py = y;
			return;
		}
	}
	*px = -1;
	*py = -1;
}
int main()
{
    
    
	int arr[3][3] = {
    
     1,2,3,4,5,6,7,8,9 };
	int k = 0;
	scanf("%d", &k);
	int x = 3;
	int y = 3;
	test(arr, k, &x, &y);
	if (x == -1 && y == -1)
		printf("找不到\n");
	else
		printf("找到了,下标是:%d %d", x, y);
	return 0;
}

二.字符串左旋

题目:实现一个函数,可以左旋字符串中的k个字符
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB

方法一:后面字符往前移动

思路:当k=1时,把原来A的位置放B,B的位置放C,C的位置放D,D的位置放A;k=2时再按前面的方式把后一个元素放在前一个元素的位置上……
需要一个“空盒子”,先把首元素放进去,然后后面的元素依次放到前一个位置上,再把“空盒子”的元素放在最后的位置上,执行以上操作k次。
在这里插入图片描述

#include <string.h>
#include <assert.h>
void test(char* str, int k)
{
    
    
	int i = 0;
	assert(str);
	for (i = 0; i < k; i++)
	{
    
    
		int j = 0;
		char t = *str;
		int len = strlen(str);
		for (j = 0; j < len - 1; j++)
		{
    
    
			*(str + j) = *(str + j + 1);
		}
		*(str + len - 1) = t;
	}
}
int main()
{
    
    
	char arr[] = "ABCD";
	int k = 0;
	scanf("%d", &k);
	test(arr, k);
	printf("%s\n", arr);
	return 0;
}

方法二:逆序思想

思路:字符串左边逆序、右边逆序,最后整体逆序,只要知道从哪开始逆序的起始位置就行。首页要知道整个字符串的大小len,假设k=2,左边逆序的起始位置从0开始,结束是k-1;右边逆序的起始位置从k开始,结束是len-1;最后整体逆序。

在这里插入图片描述

void reverse(char* left, char* right)
{
    
    
	assert(left && right);
	while (left < right)
	{
    
    
		char t = *left;
		*left = *right;
		*right = t;
		left++;
		right--;
	}
}
void test(char* str, int k)
{
    
    
	int len = strlen(str);
	k %= len;//过滤掉重复的操作
	reverse(str, str + k - 1);
	reverse(str + k, str + len - 1);
	reverse(str, str + len - 1);
}
int main()
{
    
    
	char arr[] = "abcdef";
	int k = 0;
	scanf("%d", &k);
	test(arr, k);
	printf("%s\n", arr);
	return 0;
}

结束!谢谢观看~
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/2301_77459845/article/details/131681300
今日推荐