您的位置:首页 > 理论基础 > 数据结构算法

leetcode【数据结构简介】《数组和字符串》卡片——小结

2020-04-21 21:30 886 查看

Authur Whywait 做一块努力吸收知识的海绵
想看博主的其他所有leetcode卡片学习笔记链接?传送门点这儿

文章目录

  • 2. 杨辉三角II
  • 3. 翻转字符串里的单词
  • 4. 反转字符串中的单词III
  • 5. 删除排序数组中的重复项
  • 6. 移动零
  • 《数组和字符串》卡片- 小结

    1. 旋转数组

    给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

    输入: [1,2,3,4,5,6,7] 和 k = 3
    输出: [5,6,7,1,2,3,4]
    解释:
    向右旋转 1 步: [7,1,2,3,4,5,6]
    向右旋转 2 步: [6,7,1,2,3,4,5]
    向右旋转 3 步: [5,6,7,1,2,3,4]

    暴力法

    void rotate(int* nums, int numsSize, int k){
    if(numsSize<1 || k<1 || k%numsSize==0) return;
    for(int i=0; i<k%numsSize; i++){
    int temp = nums[numsSize-1];
    for(int j=numsSize-1; j>0; j--) nums[j] = nums[j-1];
    nums[0] = temp;
    }
    return;
    }

    执行结果

    反转

    /*反转函数*/
    void reverse(int* nums, int numsSize, int a, int b){
    int low=a, high=b;
    while(low<high){
    int temp=nums[low];
    nums[low] = nums[high];
    nums[high] = temp;
    high--; low ++;
    }
    return;
    }
    /*rotate函数主体*/
    void rotate(int* nums, int numsSize, int k){
    if(numsSize<1 || k<1 || k%numsSize==0) return;
    int k0=k%numsSize;
    reverse(nums, numsSize, 0, numsSize-1);
    reverse(nums, numsSize, 0, k0-1);
    reverse(nums, numsSize, k0, numsSize-1);
    return;
    }

    利用最大公约数

    利用 最大公约数 轻松求解

    使用环状替代

    使用环状替代

    使用辅助数组

    O(n)算法,使用辅助数组,不符合题目空间复杂度O(1)的算法要求(虽然官方也给出了这种算法)

    2. 杨辉三角II

    给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

    输入: 3
    输出: [1,3,3,1]

    普通解法

    int* getRow(int rowIndex, int* returnSize){
    * returnSize = rowIndex + 1;
    int** tri = (int **) malloc (sizeof(int*) * (rowIndex+1));
    for(int i=0; i<rowIndex+1; i++){
    tri[i] = (int *) malloc (sizeof(int) * (i+1));
    tri[i][0] = 1;
    tri[i][i] = 1;
    }
    for(int i=2; i<rowIndex+1; i++){
    for(int j=1; j<i; j++){
    tri[i][j] = tri[i-1][j-1] + tri[i-1][j];
    }
    }
    return tri[rowIndex];
    }

    优化解法

    降低解法的空间复杂度

    只申请一行的空间,从后往前操作就不需要考虑被覆盖的问题。

    int* getRow(int rowIndex, int* returnSize){
    * returnSize = rowIndex + 1;
    int* array = (int *)malloc(sizeof(int) * (rowIndex+1));
    for(int i=0; i<rowIndex+1; i++){
    array[i]=1;
    for(int j=i-1; j>0; j--) array[j] = array[j] + array[j-1];
    array[0] = 1;
    }
    return array;
    }

    3. 翻转字符串里的单词

    给定一个字符串,逐个翻转字符串中的每个单词。

    输入: “the sky is blue”
    输出: “blue is sky the”

    输入: " hello world! "
    输出: “world! hello”
    解释:输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

    输入: “a good example”
    输出: “example good a”
    解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

    法一:辅助(返回)字符串+反转

    思路:
    1.除了多余空格,其他字符依次转移到辅助字符串里。
    2.反转整个字符串,再把单词依次反转。

    法二:反转-额外空间复杂度O(1)

    思路:
    1.遍历字符串,删去多余空格,同时反转单词(使用双指针

    head
    tail
    )。
    2.最后反转整个字符串。

    代码:

    void reverse(char * s, int a, int b){
    while(a<b){
    char temp=s[a];
    s[a++] = s[b];
    s[b--] = temp;
    }
    return;
    }
    char * reverseWords(char * s){
    int len=strlen(s), head=0, tail=0;
    /*删除前面多余的空格*/
    while(s[head]==' ') head++;
    for(int i=0; i<len-head; i++) s[i] = s[i+head];
    s[len-head] = '\0';
    len -= head;head = 0;
    int len1 = len;bool flag;
    if(!len1) return "";
    
    /*删除中间多余的空格并反转单词(如果最后有空格的话仍有一个空格未处理)*/
    for(int i=0; i<len+1; i++){
    printf("%d",i);
    if(i>len1) break;
    if(i==len1 && flag){//如果字符串末尾没有空格的情况
    tail=i-1;
    reverse(s, head, tail);
    }
    else if(s[i]!=' ' && s[i]!='\0'){
    if(!flag) head=i;	//若为不为空格且前面一个是空格:确定head
    flag=true;
    }
    else if(s[i]==' '){
    if(flag){
    tail=i-1;	//若为空格且前面一个不为空格:确定tail
    reverse(s, head, tail);
    flag = false;
    }
    else if(!flag){	//若为空格且前面一个也为空格,删除此空格且i--
    len1--;
    for(int j=i; j<len1; j++) s[j] = s[j+1];
    s[len1] = '\0';
    i--;
    }else;
    }else;
    }
    /*若有空格,处理字符串末尾空格*/
    if(!flag){
    len1--;
    s[len1] = '\0';
    }
    /*反转整个字符串*/
    reverse(s, 0, len1-1);
    return s;
    }

    细心的读者就会发现了,为什么有一行输出

    printf("%d",i);
    呢?因为是直接在leetcode上调试,所以要输出一些东西便于调试。结果在删除的时候遇到了问题,删除这个printf会导致程序的执行结果发生变化,真的是非常amazing了。
    最后就把带着
    printf("%d",i);
    的代码提交了~

    执行结果:

    执行时间长确是一个硬伤。

    4. 反转字符串中的单词III

    给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

    输入: “Let’s take LeetCode contest”
    输出: “s’teL ekat edoCteeL tsetnoc”

    【思路】
    翻转字符串里的单词相比就很简单了,思路相同,故直接上代码:

    void reverse(char * s, int a, int b){
    while(a<b){
    char temp=s[a];
    s[a++] = s[b];
    s[b--] = temp;
    }
    return;
    }
    char * reverseWords(char * s){
    int len=strlen(s), head=0, tail;
    if(!len) return "";
    bool flag=true;
    for(int i=0; i<len; i++){
    if(s[i]==' '){
    if(flag){
    tail = i-1;
    reverse(s, head, tail);
    }
    flag = false;
    }
    else if(s[i]!=' '){
    if(!flag) head = i;
    flag = true;
    }
    }
    reverse(s, head, len-1);
    return s;
    }

    5. 删除排序数组中的重复项

    给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
    不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

    给定数组 nums = [1,1,2],
    函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
    你不需要考虑数组中超出新长度后面的元素。

    法一:暴力双指针法

    思路:遇到重复,所有后面的元素往前移一个

    int removeDuplicates(int* nums, int numsSize){
    int len=numsSize;
    for(int i=1; i<len; i++){
    if(nums[i]==nums[i-1]){
    len--;
    for(int j=i; j<len; j++) nums[j] = nums[j+1];
    i--;
    }
    }
    return len;
    }

    法二:优化(快慢指针法)

    法一中的遇到重复就把后面全体往前移一个位置,但是如果诸如

    011111111111112
    之类的呢?就会多很多无谓的操作。
    于是,快慢指针法就应运而生。

    int removeDuplicates(int* nums, int numsSize){
    if(!numsSize) return 0;
    int slow=1, quick=1;
    while(quick<numsSize){
    if(nums[quick]!=nums[quick-1]) nums[slow++] = nums[quick++];
    else quick++;
    }
    return slow;
    }

    很明显,不管是在执行用时还是在内存消耗方面,快慢指针法都远远优于方法一。

    6. 移动零

    给定一个数组

    nums
    ,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

    输入: [0,1,0,3,12]
    输出: [1,3,12,0,0]

    快慢指针法

    直接用最优的快慢指针法

    void moveZeroes(int* nums, int numsSize){
    int num=0; int slow=0, quick=0;
    while(quick<numsSize){
    if(nums[quick]) nums[slow++] = nums[quick++];
    else{
    quick++;
    num++;
    }
    }
    for(int i=numsSize-num; i<numsSize; i++) nums[i]=0;
    return;
    }

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    Whywait_1 发布了44 篇原创文章 · 获赞 26 · 访问量 2054 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: 
    相关文章推荐