目录
前言:
前段时间学习了杨氏矩阵、字符串左旋,给大家分享下这两个用代码是如何实现的(文字+画图分析)
—————————————————————————————
一.杨氏矩阵
题目:有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵的每列从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于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;
}
结束!谢谢观看~