• 数据结构OJ题


    目录

    1.字符串左旋 

    2.字符串旋转结果

    3.旋转数组

    4.移除元素


    本篇主要是讲解一些OJ题目。

    1.字符串左旋 

    字符串左旋

    实现一个函数,可以左旋字符串中的k个字符

    例如:

    ABCD左旋一个字符得到BCDA

    ABCD左旋两个字符得到CDAB

    方法1【暴力求解】

    • 翻转1个字符
    1. 创建一个中间变量tmp,用于存储翻转的字符
    2. 把后面的字符向前覆盖移动
    3. 把tmp存储的字符放到结尾
    • 翻转k个字符,循环k次即可 
    • 注意如果旋转超出数组的元素个数范围,需要现处理一下。k=%len
    1. #include
    2. void left_move(char* arr, int sz,int k)
    3. {
    4. int i = 0;
    5. for (i = 0; i < k; i++)//k次
    6. {
    7. //一次翻转
    8. char tmp = 0;//1.
    9. tmp = *arr;
    10. int j = 0;//2.
    11. for (j = 0; j < sz - 2; j++)
    12. {
    13. arr[j] = arr[j + 1];
    14. }
    15. arr[sz - 2] = tmp;//3.
    16. }
    17. }
    18. int main()
    19. {
    20. char arr[] = "ABCDEF";
    21. int sz = sizeof(arr) / sizeof(arr[0]);//计算了\0
    22. int k = 0;
    23. scanf_s("%d", &k);
    24. k = k % (sz - 1);
    25. left_move(arr, sz,k);
    26. printf("%s", arr);
    27. return 0;
    28. }


    方法2【三步翻转】

    • 左边逆序
    • 右边逆序
    • 整体逆序
    • 封装一个逆序字符串的函数,传不同的起尾位置,调用三次函数即可
    • 注意如果旋转超出数组的元素个数范围,会造成数组越界的问题,需要现处理一下。k=%len
    1. #include
    2. //逆序字符串函数
    3. void reverse(char* begin, char* end)
    4. {
    5. while (begin < end)
    6. {
    7. char tmp = 0;
    8. tmp = *begin;
    9. *begin = *end;
    10. *end = tmp;
    11. begin++;
    12. end--;
    13. }
    14. }
    15. int main()
    16. {
    17. char arr[] = "ABCDEF";
    18. int sz = sizeof(arr)/sizeof(arr[0]);
    19. int k = 0;
    20. scanf_s("%d", &k);
    21. k = k % (sz - 1);//必须有不然会数组越界
    22. reverse(arr, arr + k-1);
    23. reverse(arr + k, arr + sz - 2);
    24. reverse(arr, arr + sz - 2);
    25. printf("%s", arr);
    26. return 0;
    27. }


    2.字符串旋转结果

    字符串旋转结果

    写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。

    例如:

    给定s1= AABCD和s2 = BCDAA,返回1

    给定s1=abcd和s2=ABCD,返回0

    方法1【暴力求解】

    • 旋转1次比较1次
    • 把所有结果都列出来一一比较,如果没有那就返回0.
    • 注意:如果两个数组的长度不一样,是肯定不会旋转得到的,需要处理一下。
    1. #include
    2. #include
    3. #include
    4. int is_left_move(char* arr1, const char* arr2)
    5. {
    6. assert(arr1 && arr2);
    7. int len1 = strlen(arr1);
    8. int len2 = strlen(arr2);
    9. if (len1 != len2)
    10. {
    11. return 0;
    12. }
    13. int i = 0;
    14. //这里如果用while len是变化的
    15. for(i=0;i
    16. {
    17. //一次翻转
    18. char tmp = 0;//1.
    19. tmp = *arr1;
    20. int j = 0;//2.
    21. for (j = 0; j < len1 - 1; j++)
    22. {
    23. arr1[j] = arr1[j + 1];
    24. }
    25. arr1[len1 - 1] = tmp;//3
    26. //判断
    27. if (strcmp(arr1, arr2) == 0)
    28. {
    29. return 1;
    30. }
    31. }
    32. return 0;
    33. }
    34. int main()
    35. {
    36. char arr1[] = "ABCDEF";
    37. char arr2[] = "CDEFAB";
    38. int ret=is_left_move(arr1, arr2);
    39. if (ret == 1)
    40. {
    41. printf("YES");
    42. }
    43. else
    44. {
    45. printf("NO");
    46. }
    47. return 0;
    48. }

     


    方法2【追加找子串 】

    • 把原字符串数组arr1追加,这样翻转所有的可能性都在追加字符串里
    • 再去arr1追加字符串里找子串arr2,看是否和要比较字符串数组arr2,相符号的。
    • 注意:如果两个数组的长度不一样,是肯定不会旋转得到的,需要处理一下。
    1. #include
    2. #include
    3. #include
    4. int is_left_move(char* arr1, const char* arr2)
    5. {
    6. assert(arr1 && arr2);
    7. int len1 = strlen(arr1);
    8. int len2 = strlen(arr2);
    9. if (len1 != len2)
    10. {
    11. return 0;
    12. }
    13. int len = strlen(arr1);
    14. strncat(arr1, arr1, len);
    15. if (strstr(arr1, arr2) == NULL)
    16. return 0;
    17. else
    18. return 1;
    19. }
    20. int main()
    21. {
    22. char arr1[] = "ABCDEF";
    23. char arr2[] = "CDEFAB";
    24. int ret=is_left_move(arr1, arr2);
    25. if (ret == 1)
    26. {
    27. printf("YES");
    28. }
    29. else
    30. {
    31. printf("NO");
    32. }
    33. return 0;
    34. }


    3.旋转数组

    给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

    输入: nums = [1,2,3,4,5,6,7], k = 3
    输出: [5,6,7,1,2,3,4]
    输入:nums = [-1,-100,3,99], k = 2
    输出:[3,99,-1,-100]
    

    方法1【暴力求解】

    同上

    时间复杂度:O(N^2)

    1. #include
    2. #include
    3. #include
    4. void right_move(char* arr,int k)
    5. {
    6. assert(arr);
    7. int len = strlen(arr);
    8. k%=len;
    9. int i = 0;
    10. for (i = 0; i < k; i++)
    11. {
    12. int j = 0;
    13. char tmp = arr[len - 1];
    14. for (j = len-1; j >0; j--)
    15. {
    16. arr[j] = arr[j -1];
    17. }
    18. *arr = tmp;
    19. }
    20. }
    21. int main()
    22. {
    23. char arr[] = "ABCDEF";
    24. int k = 0;
    25. scanf("%d", &k);
    26. right_move(arr,k);
    27. printf("%s", arr);
    28. return 0;
    29. }


    方法2【三步翻转】

    界限:需要右旋&不需要右旋的逆置,整体逆置

    时间复杂度:O(N) 

    1. #include
    2. //逆序字符串函数
    3. void reverse(char* begin, char* end)
    4. {
    5. while (begin < end)
    6. {
    7. char tmp = 0;
    8. tmp = *begin;
    9. *begin = *end;
    10. *end = tmp;
    11. begin++;
    12. end--;
    13. }
    14. }
    15. int main()
    16. {
    17. char arr[] = "ABCDEF";
    18. int len = strlen(arr);
    19. int k = 0;
    20. scanf_s("%d", &k);
    21. k = k % len;//必须有不然会数组越界
    22. reverse(arr,arr+len-k-1);
    23. reverse(arr+len-k,arr+len-1);
    24. reverse(arr,arr+len-1);
    25. printf("%s", arr);
    26. return 0;
    27. }

    方法3【以时间换空间】

    • 先拷贝前len-k个到后面位置
    • 再拷贝k个 到前面位置
    • 最后拷贝回去
    • 变长数组和动态内存开辟的数组都可
    • 关键就是下标和位置一定一定控制清楚
    • 时间复杂度:O(N)       空间复杂度:O(N)

    1. void rotate(int* nums, int numsSize, int k)
    2. {
    3. int tmp[numsSize];
    4. int i=0;
    5. k%=numsSize;//就这个代码卡了我一下午,有时候真的很无助
    6. for(i=0;i
    7. {
    8. *(tmp+i)=*(nums+numsSize-k+i);
    9. }
    10. for(i=0;i
    11. {
    12. *(tmp+k+i)=*(nums+i);
    13. }
    14. for(i=0;i
    15. {
    16. *(nums+i)=*(tmp+i);
    17. }
    18. }

     


    4.移除元素

    给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

    输入:nums = [3,2,2,3], val = 3
    输出:2, nums = [2,2]
    解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
    

    方法1【暴力求解】

    • 首先遍历数组一遍找到元素
    • 从后向前依次覆盖
    • 时间复杂度:O(N^2)
    1. int removeElement(int* nums, int numsSize, int val)
    2. {
    3. int i=0;
    4. for(i=0;i
    5. {
    6. if(nums[i] == val)
    7. {
    8. for(;i//❌
    9. nums[i]=nums[i+1];
    10. }
    11. }
    12. return numsSize;
    13. }

    方法2【以空间换时间】

    • 创建一个一摸一样的数组tmp
    • 把是val的数值元素留下,不是的拷贝到tmp中
    • 最后把tmp拷贝到nums里面去
    • 时间复杂度:O(N)

     但是我们发现,题目要求不允许这么做?怎么办呢? 


    方法3【方法2的优化】

    那我们选择就在nums的基础上实现tmp等的功能。

    • 使用src指针和des指针
    • 时间复杂度O(N)

    1. int removeElement(int* nums, int numsSize, int val){
    2. int src=0;
    3. int dst=0;
    4. while(src
    5. {
    6. if(nums[src] != val)
    7. {
    8. nums[dst++]=nums[src++];
    9. }
    10. else
    11. {
    12. src++;
    13. }
    14. }
    15. return dst;
    16. }

    【暴力求解】&【三步翻转】 

    【注意】 

    • len&sz
    • 指针&数组下标
    • 如果找错了位置或者减少了都会发生错误❌

    ✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正! 棠棣

    代码---------→【唐棣棣 (TSQXG) - Gitee.com

    联系---------→【邮箱:2784139418@qq.com】

  • 相关阅读:
    配置nginx域名转发
    密码相关----对称加密,非对称加密
    A Survey of Knowledge-Enhanced Pre-trained Language Models
    大数据实训2 - 法律咨询数据分析和服务推荐
    C#数据类型
    Java多线程篇(11)——BlockingQueue(优先级阻塞,延迟队列)
    新唐NUC980使用记录:U-Boot & Linux 编译与烧录(基于SPI NAND)
    通过 Grafana 对prometheus 监控做可视化
    《网络协议》08. 概念补充
    DataFrame(11):数据转换——map()函数的使用
  • 原文地址:https://blog.csdn.net/m0_74841364/article/details/134087492