多方法超度旋转数组——LeetCode算法题解

简介: 正片开始👀LeetCode链接:https://leetcode-cn.com/problems/rotate-array/

image.png

首先这个中等难度我是没搞懂,后面才发现原来中等中在要求多方法上,那就来看看怎么搞定他吧。


暴力思路👏

首先我说一下我本人的思路,就是函数进行倒序操作,分三步:

1.整体倒序 :1234567-------7654321

2.前半部分倒序:7654321------- 5674321

3.后半部分倒序:5674321-------5671234


由于题目已经给出了我们 k 的值,我们直接暴力思路(注意是暴力思路非暴力求解),双指针交换对应的值就行:

void exchange(int* a, int* b)
{
int n=*a;
*a = *b;
*b = n;
}   //交换a,b位置
void reverse(int* nums,int left,int right)
{
while(left<right)
{
exchange(&nums[left],&nums[right]);
left++;
right--;
}   //对指定范围内元素进行翻转操作
}
void rotate(int* nums, int numsSize, int k){
k%=numsSize;
if(k==0)
{
return ;  //防止k过大或0导致无意义操作
}
reverse(nums,0,numsSize-1);//全倒序
reverse(nums,0,k-1);//前半部分倒序
reverse(nums,k,numsSize-1);//后半部分倒序
}

这种方法直观,最容易想到,特点是思路清晰,完美符合了流程,时间复杂度是O(n),空间复杂度是O(1),将将就就


外加数组👏

自力更生不想要咱就寻求外援嘛,直接创建一个额外数组,前半部分放前面,后半部分放后面不就行了,用 numsSize 表示数组的长度,我们遍历原数组,将原数组下标为 n 的元素放至新数组下标为 n+k 的位置,最后将新数组拷贝至原数组即可:

void rotate(int* nums, int numsSize, int k){
int arr[numsSize] = {0};
for(int n = 0;n<numsSize;n++)
{
arr[(k+n)%numsSize] = nums[n]; //nums所有元素向前移动 k 个单位,依次存到数组arr
}
for(int n = 0;n<numsSize;n++)
{
nums[n] = arr[n];  //将arr数组内容拷贝回原数组nums
}

同理,我们可以选择直接 malloc 一块空间出来,这种方法同上不赘述


格局抬高👏

既然我们能想到 malloc 开辟空间操作,那再想想库函数里面好像还有个好东西叫 memcpy ,头文件:#include <string.h>,memcpy() 用来复制内存,且忽略 \0,其原型为:

  void * memcpy ( void * dest, const void * src, size_t num );

memcpy() 会复制 src 所指的内存内容的前 num 个字节到 dest 所指的内存地址上。memcpy() 并不关心被复制的数据类型,只是逐字节地进行复制,这给函数的使用带来了很大的灵活性,可以面向任何数据类型进行复制。

代码如下:

void rotate(int* nums, int numsSize, int k){
int arr[numsSize];
k %= numsSize;
memcpy(arr,nums+(numsSize-k),k*(int)sizeof(int));
memcpy(arr+k,nums,(numsSize-k)*(int)sizeof(int));
memcpy(nums,arr,numsSize*(int)sizeof(int));
}

但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法,所以可能会有一个疑问就是为什么不用 memmove?


memmove 相比 memcpy 更容易造成数据丢失。如果目标区域和源区域有重叠的话,memmove() 能保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。


强调一下,与 strcpy() 不同的是,memcpy() 会完整的复制 num 个字节,不会因为遇到“\0”而结束。


环形替代

image.png

这是力扣上官方给出的一种方法,需要数学推导,比较难理解,解析给的是花里胡哨,添油加醋的,我大概概括一下就是把数组一串元素类比成莫比乌斯环,我们构图理解就简单多了(ppt手绘勿喷):

image.png

什么意思呢,就是我们就拿k作为遍历间隔,不断拿 1+nk(n从0开始) 位置的元素替代 1+ (n+1)k位置元素,直到回到原点,回到原点时因为遍历间隔>0,必定会有未遍历的元素我们只需+1 跳到下一位置继续上述操作,再使用另一单独变量,跟踪当前已经访问的元素数量,当该变量 = 元素数量时遍历完成,结束遍历过程。(个人理解,如有不当请联系我更正哟~)

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}
void swap(int* a, int* b) {
    int t = *a;
    *a = *b, *b = t;
}
void rotate(int* nums, int numsSize, int k) {
    k = k % numsSize;
    int count = gcd(k, numsSize);
    for (int start = 0; start < count; ++start) {
        int current = start;
        int prev = nums[start];
        do {
            int next = (current + k) % numsSize;
            swap(&nums[next], &prev);
            current = next;
        } while (start != current);
    }
}
相关文章
|
29天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
9天前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
30 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
1月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
23 2
|
1月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
37 2
|
1月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
19 4
|
1月前
|
存储 算法 Java
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
前缀(波兰)表达式、中缀表达式和后缀(逆波兰)表达式的基本概念、计算机求值方法,以及如何将中缀表达式转换为后缀表达式,并提供了相应的Java代码实现和测试结果。
46 0
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
|
1月前
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
20 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
1月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
18 0
Leetcode第三十三题(搜索旋转排序数组)