数组题总结

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

法一:统计0元素

nums=[1,2,0,3,9,0,]
def MoveZeroes(self):
        """
        Do not return anything, modify nums in-place instead.
        """
        # 循环记录0元素的个数,并且遇到非0元素时候,将非0元素替换到0元素的位置
        # count 记录0元素的个数, i - count实际上是记录了零元素的位置。
        count = 0
        for i in range(len(nums)):
            if nums[i] == 0:
                count += 1
            elif count > 0:
                nums[i - count], nums[i] = nums[i], 0
        return nums

output=MoveZeroes(nums)
print(output) 

复杂度分析:时间复杂度:O(n),假设有n个元素需要遍历n次
空间复杂度:O(1),只是对原数组进行替换操作

法二:双指针滑动,交换非零元素和零元素的位置

class Solution:
    def moveZeroes(self,arg) :
        # 循环遍历数组,当遇到非零元素则开始交换慢指针所指的0元素
        # i 为慢指针 指向最新一个0元素的位置
        i = 0
        for j in range(len(nums)):
            if nums[j] != 0:
                nums[i], nums[j] = nums[j], nums[i]
                i += 1

        return nums

nums=[1,2,0,3,9,0]
output=Solution()
print(output.moveZeroes(nums))

>>>[1, 2, 3, 9, 0, 0]
改成[1, 2, 8, 3, 9, 0]
print一下打印出中间的num[i],num[j]可得
2
1
======
8
2
======
3
8
======
9
3
======
0
9
======
0
0
======
[1, 2, 8, 3, 9, 0]

Process finished with exit code 0

快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。
时间复杂度:O(n),假设有n个元素需要遍历n次
空间复杂度:O(1),只是对原数组进行替换操作

法三:非零元素替换零元素法

class Solution:
    def moveZeroes(self,arg) :
        # 循环遍历数组,当遇到非零元素则开始交换慢指针所指的0元素
        # i 为慢指针 指向最新一个0元素的位置
        j = 0
        for i in range(len(nums)):
            if nums[i] != 0:
                nums[j] = nums[i]
                if i != j:
                    nums[i] = 0
                j += 1
            print(nums[i])
            print(nums[j])
            print('======')

        return nums

nums=[1,2,8,3,9,0]
output=Solution()
print(output.moveZeroes(nums))
>>>
1
2
======
2
8
======
8
3
======
3
9
======
9
0
======
0
0
======
[1, 2, 8, 3, 9, 0]
但凡中间出现0 就会后面全部变成0
如:
2
1
======
0
2
======
0
0
======
0
0
======
0
0
======
0
0
======
[1, 2, 3, 9, 0, 0]


时间复杂度:O(n),假设有n个元素需要遍历n次
空间复杂度:O(1),只是对原数组进行替换操作

### 关于C语言中指针数组关练习解析 以下是针对C语言中指针数组的一些经典目及其解析: #### 目一:二级指针传参 ```c #include<stdio.h> void test(int** ptr) { printf("num=%d\n", **ptr); } int main() { int n = 10; int* p = &n; int** pp = &p; test(&p); // 输出 num=10 test(pp); // 输出 num=10 int* arr[10] = {0}; test(arr); // 编译错误或未定义行为,因为arr是一个指针数组而非二级指针。 return 0; } ``` 上述代码展示了如何传递二级指针函数并打印其值。`test(&p)` 和 `test(pp)` 的功能同,都是将地址的地址作为参数传递给函数[^1]。然而,在调用 `test(arr)` 时会引发编译器警告或者运行时错误,这是因为 `arr` 是一个指针数组而不是二级指针。 --- #### 目二:函数指针数组的应用 假设我们有一个简单的计算器程序,其中包含了加、减、乘、除四个操作,并将其封装成函数指针数组的形式: ```c #include <stdio.h> // 定义基本运算函数 int add(int a, int b) { return a + b; } int subtract(int a, int b) { return a - b; } int multiply(int a, int b) { return a * b; } int divide(int a, int b) { return b != 0 ? (a / b) : 0; } // 创建函数指针数组 typedef int (*FuncPtr)(int, int); int main() { FuncPtr operations[] = {add, subtract, multiply, divide}; // 函数指针数组初始化 const char* operationNames[] = {"Addition", "Subtraction", "Multiplication", "Division"}; int opIndex = 2; // 假设用户选择了第3项(索引为2) int result = operations[opIndex](8, 4); // 调用对应的操作符 printf("%s of %d and %d is %d\n", operationNames[opIndex], 8, 4, result); return 0; } ``` 此代码片段展示了一个典型的函数指针数组应用案例。通过选择不同的索引来执行应的算术运算[^2]。 --- #### 目三:双指针法处理平方后的非递减序列 对于一个已排序但可能包含负数的整型数组,我们需要返回一个新的数组,该数组中的元素为其原始数值的平方且保持非递减顺序。 ```c #include <stdio.h> void sortedSquares(int nums[], int size, int results[]) { int i = 0, j = size - 1, k = size - 1; while(i <= j){ if(nums[i]*nums[i] >= nums[j]*nums[j]){ results[k--] = nums[i]*nums[i]; ++i; }else{ results[k--] = nums[j]*nums[j]; --j; } } } int main(){ int inputArray[] = {-7,-3,2,3,11}; int outputArray[sizeof(inputArray)/sizeof(int)]; int length = sizeof(inputArray)/sizeof(int); sortedSquares(inputArray,length,outputArray); for(int m=0;m<length;++m){ printf("%d ",outputArray[m]); } return 0; } ``` 这段代码实现了利用双指针方法解决此类问的功能[^3]。它从两端向中心遍历输入数组同时构建结果数组,从而避免了额外的时间复杂度开销。 --- ### 总结 以上三个例子分别涉及到了不同层次上的指针运用技巧以及实际应用场景下的算法实现方式。这些内容不仅有助于初学者理解基础概念,也能帮助有经验开发者巩固高级特性掌握情况[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值