LeetCode(1089)复写零

话在前:(1)题目描述         (2)解题思路         (3)代码和结果

(1)题目描述:

给你一个长度固定的整数数组 arr,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。

要求:请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

示例 1:

输入:[1,0,2,3,0,4,5,0]
输出:null
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]
示例 2:

输入:[1,2,3]
输出:null
解释:调用函数后,输入的数组将被修改为:[1,2,3]

提示:

1 <= arr.length <= 10000
0 <= arr[i] <= 9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/duplicate-zeros
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

(2)解题思路

方法1:用循环去遍历零,遇零则先移位后面的数据,再写零到下一个位置。

思考:这是大多数人第一眼的想法,但是我认为这道题考的就是不能这么去做,因为时间几乎就是耗在移位上的,特别是当数据量很大的时候,想想都恐怖!

方法2:先copy原数组,再去选择插入。

思考:细想的话应该是没问题的,但是我不敢细想,因为数据量大了,比如一个T,你去复制???

然后得到最终的方法:

先遍历数组,得到所有零的下标,下标值存在一个index数组中;

再根据零的个数,去决定下一个循环处理的次数,在处理循环中,核心就是计算零在移位后应该的位置(暂不考虑溢出)zero_pos,然后区分zero_pos在原数组末尾的相对位置:

(zero_pos < (arrsize-1) 、zero_pos = (arrsize-1)、zero_pos > (arrsize-1))

最后根据这三种情况去对每个小unit(一个零到下一个零  or  一个零到数组边界)做处理,处理细节见代码吧(看不懂的可以留言,谢谢)

(3)代码和结果//附有完整测试代码,可在本地自测

#include <stdio.h>

void duplicateZeros(int* arr, int arrSize)
{
    size_t i, j, count, s1, s2, j_src, tmp_len = 0, zero_pos = 0;
    unsigned int index[arrSize];

    //memset(index, 0, sizeof(index));
    //step1:find the indx of zero
    for (j = 0, i = 0; i < arrSize; ++i){
        if (arr[i] == 0)
            index[j++] = i;
    }
    int arrlen = arrSize - 1;
    //step2:change data from tail to head
    j_src = j;
    for ( ; j > 0; --j){
        zero_pos = ((j - 1) + index[j - 1]);
        if ( zero_pos == (arrlen)){//the zero on the tail
            arr[arrlen] = 0;
        }
        else{
            if( zero_pos > (arrlen) ){//the zero out of tail
                if( ((j-1) > 0) && ( ((j - 2) + index[j - 2]) < (arrlen)) ){
                    tmp_len = (arrlen ) - ((j - 2) + index[j - 2]) - 1;
                }
            }
            else{//the zero in tail
                if( tmp_len > 0 ){
                    count = tmp_len;
                    tmp_len = 0;
                }
                else{
                    if( j == j_src )
                        count = arrSize - index[j-1] - 1;
                    else 
                        count = index[j] - index[j-1] - 1;
                }
                    
                s1 = zero_pos + 2 + count - 1;
                s2 = 1 + index[j-1] + count - 1;
                if( s1 > (arrlen) ){
                     count = count - (s1 - (arrlen));
                     s1 = zero_pos + 2 + count - 1;
                     s2 = 1 + index[j-1] + count - 1;
                }
                    
                for ( i = 0; i < count; i++){
                    arr[s1--] = arr[s2--];
                }

                arr[zero_pos] = 0;
                arr[zero_pos+1] = 0;
            }     
        }
    }
}

unsigned int arr[] = {1, 2, 0, 3, 0, 4, 5, 0, 6, 7};
unsigned int arr_ex[] = {1, 0, 2, 3, 0, 4, 5, 0};
unsigned int arr_ex2[] = {8, 5, 0, 9, 0, 3, 4, 7};
#define dest_arr arr_ex2

int main(void)
{
    size_t i;

    printf_s("the arrary of int:\n");
    size_t count = sizeof(dest_arr) / sizeof(int);
    for (i = 0; i < count; i++){
        printf_s("%d ", dest_arr[i]);
    }
    printf_s("\n");

    printf_s("after dup_zero:\n");
    duplicateZeros(dest_arr, count);
    for (i = 0; i < count; i++){
        printf_s("%d ", dest_arr[i]);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值