当前位置: 首页 > news >正文

LeeCode 283. 移动零

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

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

示例 2:

输入: nums = [0]
输出: [0]

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1

进阶:你能尽量减少完成的操作次数吗?

代码如下:

写了一个仿照java ArrayList的 可变长数组的数据结构。为了验证,就用它实现本题功能。

IntArrayList.h 头文件:

#ifndef INT_ARRAY_LIST_H
#define INT_ARRAY_LIST_H

// 头文件添加跨语言支持
#ifdef __cplusplus
extern "C" {
#endif

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include <string.h>

typedef int (*Compare)(int, int); // 比较函数,用于排序

typedef struct {
	int* data;
	int size; // 当前长度,即有多少条数据。
	int capacity; // 实际数组长度
}IntArrayList;

IntArrayList* CreateIntArrayList(int initialCapacity);

void FreeIntArrayList(IntArrayList* list);

void ClearIntArrayList(IntArrayList* list);

// 获取指定索引处的数据,因为不修改结构体数据,所以参数list加const修饰
int GetIntArrayList(const IntArrayList* list, int pos);

bool InsertIntArrayList(IntArrayList* list, int val, int pos);

bool AddIntArrayList(IntArrayList* list, int val);

bool SetIntArrayList(IntArrayList* list, int val, int pos);

bool DeleteIntArrayList(IntArrayList* list, int pos);

bool ContainsIntArrayList(const IntArrayList* list, int val);

int SizeIntArrayList(const IntArrayList* list);

void SortIntArrayList(IntArrayList* list, Compare compare);

#ifdef __cplusplus
}
#endif

#endif

相应的,在源文件IntArrayList.c中完成函数定义:

#include "IntArrayList.h"

// 检查数组容量, 容量不够就扩容。 为隐藏内部函数,加static修饰
static bool ensureCapacity(IntArrayList* list) {
	if (list->size == list->capacity) { // 实际储存的数据量已经把数组撑满了。
		int newCapacity = list->capacity << 1; // 为降低扩容频率,每次容量增加1倍
		int* newData = (int*)realloc(list->data, newCapacity * sizeof(int)); // 
		if (!newData) {
			fprintf(stderr, "Memory allocation failed\n");
			//exit(EXIT_FAILURE); // 内存分配失败时退出程序
			return false;
		}
		else {
			list->data = newData;
			list->capacity = newCapacity;
		}
	}
	return true;
}

IntArrayList* CreateIntArrayList(int initialCapacity) {
	IntArrayList* list = (IntArrayList*)malloc(sizeof(IntArrayList)); // 堆分配
	if (list == NULL) {
		fprintf(stderr, "Memory allocation failed\n");
		exit(EXIT_FAILURE);
	}
	list->data = (int*)malloc(initialCapacity * sizeof(int));
	if (list->data == NULL) {
		fprintf(stderr, "Memory allocation failed\n");
		exit(EXIT_FAILURE); // 内存分配失败时退出程序
	}
	list->capacity = initialCapacity;
	list->size = 0;
	return list;
}

bool AddIntArrayList(IntArrayList* list, int val) {
	return InsertIntArrayList(list, val, SizeIntArrayList(list));
}

void FreeIntArrayList(IntArrayList* list) {
	free(list->data);
	list->data = NULL; // 将指针设置为NULL以避免悬挂指针问题。
	list->size = 0;
	list->capacity = 0;
	free(list);
}

void ClearIntArrayList(IntArrayList* list) {
	list->size = 0;
}

int GetIntArrayList(const IntArrayList* list, int pos) {
	if (pos >= list->size || pos < 0) {
		// 越界了
		fprintf(stderr, "out of index\n");
		exit(EXIT_FAILURE);
	}
	return list->data[pos];
}

bool InsertIntArrayList(IntArrayList* list, int val, int pos) {
	if (!ensureCapacity(list))
		return false;
	if (pos < 0 || pos > list->size) {
		fprintf(stderr, "InsertIntArrayList, out of index\n");
		printf("InsertIntArrayList, out of index , pos: %d, size: %d \n", pos, list->size);
		return false;
	}
	if (pos == list->size) {
		// 添加在最后,无需移动其他数据位置
		list->data[pos] = val;
		list->size++;
		return true;
	}
	// 在pos索引处插入数据,其他数据需要往后移动.
	// 先利用memmove函数移动数组中元素
	memmove(&list->data[pos + 1], &list->data[pos], (list->size - pos) * sizeof(int));
	list->data[pos] = val;
	list->size++;
	return true;
}

bool SetIntArrayList(IntArrayList* list, int val, int pos) {
	if (pos < 0 || pos >= list->size) {
		fprintf(stderr, "out of index\n");
		return false;
	}
	list->data[pos] = val;
	return true;
}

bool DeleteIntArrayList(IntArrayList* list, int pos) {
	if (pos < 0 || pos >= list->size) {
		fprintf(stderr, "out of index\n");
		return false;
	}
	if (pos == list->size - 1) {
		// 移动的是最后一个
		list->size--;
		return true;
	}
	// 将索引pos以及之后所有元素向前移动一个
	memmove(&list->data[pos], &list->data[pos + 1], (list->size - pos - 1) * sizeof(int));
	list->size--;
	return true;
}

bool ContainsIntArrayList(const IntArrayList* list, int val) {
	for (int i = 0; i < list->size; i++) {
		if (list->data[i] == val)
			return true;
	}
	return false;
}

int SizeIntArrayList(const IntArrayList* list) {
	return list->size;
}

void SortIntArrayList(IntArrayList* list, Compare compare) {
	if (!list || list->size < 2)
		return;
	if (!compare) {
		printf("没传比较函数!\n");
		return;
	}
	// 先随便想个排序,用冒泡,后面优化为插入法或其他排序方法
	int temp;
	for (int i = 0; i < list->size - 1; i++) {
		// 提前退出冒泡循环的标志位
		int swapped = 0;
		for (int j = 0; j < list->size - 1 - i; j++) {
			if (compare(list->data[j], list->data[j+1]) > 0){
				temp = list->data[j];
				list->data[j] = list->data[j+1];
				list->data[j + 1] = temp;
				swapped = 1; // 表示发生了交换
			}
		}
		// 如果没有数据交换,数组已经有序,不需要再继续执行循环
		if (!swapped) {
			break;
		}
	}
}

代码:

#include <stdio.h>
#include <stdlib.h>
#include "IntArrayList.h"

int compareFunZeroToLast(int a, int b) { // 目的是排序时把0排到最后
	if (a == 0 && b != 0)
		return 1;
	return 0;
}

void moveZeroes(int* nums, int numsSize) { // LeeCode283. 移动零
	IntArrayList* list = CreateIntArrayList(numsSize); 
	for (int i = 0; i < numsSize; i++) {
		if (!AddIntArrayList(list, nums[i])) {
			fprintf(stderr, "Failed to add element %d\n", nums[i]);
			FreeIntArrayList(list);
			return;
		}
	}
	SortIntArrayList(list, compareFunZeroToLast); // 关键是排序
	for (int i = 0; i < numsSize; i++) {
		nums[i] = GetIntArrayList(list, i); // 保存最终结果
	}
}

测试代码:

void testLeeCode283() {
	int nums[] = {0, 1, 0, 3, 12};
	moveZeroes(nums, sizeof(nums) / sizeof(nums[0]));
	printf("结果: \n");
	for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
		printf("%d \n", nums[i]);
	}
}

打印:

ok。结果正确。

提交到LeeCode,因为LeeCode不能提交多个文件,所以代码合到一起,这样提交:

int compareFunZeroToLast(int a, int b) { // 目的是排序时把0排到最后
	if (a == 0 && b != 0)
		return 1;
	return 0;
}

typedef int (*Compare)(int, int); // 比较函数,用于排序

typedef struct {
	int* data;
	int size; // 当前长度,即有多少条数据。
	int capacity; // 实际数组长度
}IntArrayList;

// 检查数组容量, 容量不够就扩容。 为隐藏内部函数,加static修饰
static bool ensureCapacity(IntArrayList* list) {
	if (list->size == list->capacity) { // 实际储存的数据量已经把数组撑满了。
		int newCapacity = list->capacity << 1; // 为降低扩容频率,每次容量增加1倍
		int* newData = (int*)realloc(list->data, newCapacity * sizeof(int)); // 
		if (!newData) {
			fprintf(stderr, "Memory allocation failed\n");
			//exit(EXIT_FAILURE); // 内存分配失败时退出程序
			return false;
		}
		else {
			list->data = newData;
			list->capacity = newCapacity;
		}
	}
	return true;
}

IntArrayList* CreateIntArrayList(int initialCapacity) {
	IntArrayList* list = (IntArrayList*)malloc(sizeof(IntArrayList)); // 堆分配
	if (list == NULL) {
		fprintf(stderr, "Memory allocation failed\n");
		exit(EXIT_FAILURE);
	}
	list->data = (int*)malloc(initialCapacity * sizeof(int));
	if (list->data == NULL) {
		fprintf(stderr, "Memory allocation failed\n");
		exit(EXIT_FAILURE); // 内存分配失败时退出程序
	}
	list->capacity = initialCapacity;
	list->size = 0;
	return list;
}

void FreeIntArrayList(IntArrayList* list) {
	free(list->data);
	list->data = NULL; // 将指针设置为NULL以避免悬挂指针问题。
	list->size = 0;
	list->capacity = 0;
	free(list);
}

void ClearIntArrayList(IntArrayList* list) {
	list->size = 0;
}

int GetIntArrayList(const IntArrayList* list, int pos) {
	if (pos >= list->size || pos < 0) {
		// 越界了
		fprintf(stderr, "out of index\n");
		exit(EXIT_FAILURE);
	}
	return list->data[pos];
}

bool InsertIntArrayList(IntArrayList* list, int val, int pos) {
	if (!ensureCapacity(list))
		return false;
	if (pos < 0 || pos > list->size) {
		fprintf(stderr, "InsertIntArrayList, out of index\n");
		printf("InsertIntArrayList, out of index , pos: %d, size: %d \n", pos, list->size);
		return false;
	}
	if (pos == list->size) {
		// 添加在最后,无需移动其他数据位置
		list->data[pos] = val;
		list->size++;
		return true;
	}
	// 在pos索引处插入数据,其他数据需要往后移动.
	// 先利用memmove函数移动数组中元素
	memmove(&list->data[pos + 1], &list->data[pos], (list->size - pos) * sizeof(int));
	list->data[pos] = val;
	list->size++;
	return true;
}

bool SetIntArrayList(IntArrayList* list, int val, int pos) {
	if (pos < 0 || pos >= list->size) {
		fprintf(stderr, "out of index\n");
		return false;
	}
	list->data[pos] = val;
	return true;
}

bool DeleteIntArrayList(IntArrayList* list, int pos) {
	if (pos < 0 || pos >= list->size) {
		fprintf(stderr, "out of index\n");
		return false;
	}
	if (pos == list->size - 1) {
		// 移动的是最后一个
		list->size--;
		return true;
	}
	// 将索引pos以及之后所有元素向前移动一个
	memmove(&list->data[pos], &list->data[pos + 1], (list->size - pos - 1) * sizeof(int));
	list->size--;
	return true;
}

bool ContainsIntArrayList(const IntArrayList* list, int val) {
	for (int i = 0; i < list->size; i++) {
		if (list->data[i] == val)
			return true;
	}
	return false;
}

int SizeIntArrayList(const IntArrayList* list) {
	return list->size;
}

bool AddIntArrayList(IntArrayList* list, int val) {
	return InsertIntArrayList(list, val, SizeIntArrayList(list));
}

void SortIntArrayList(IntArrayList* list, Compare compare) {
	if (!list || list->size < 2)
		return;
	if (!compare) {
		printf("没传比较函数!\n");
		return;
	}
	// 先随便想个排序,用冒泡,后面优化为插入法或其他排序方法
	int temp;
	for (int i = 0; i < list->size - 1; i++) {
		// 提前退出冒泡循环的标志位
		int swapped = 0;
		for (int j = 0; j < list->size - 1 - i; j++) {
			if (compare(list->data[j], list->data[j+1]) > 0){
				temp = list->data[j];
				list->data[j] = list->data[j+1];
				list->data[j + 1] = temp;
				swapped = 1; // 表示发生了交换
			}
		}
		// 如果没有数据交换,数组已经有序,不需要再继续执行循环
		if (!swapped) {
			break;
		}
	}
}

void moveZeroes(int* nums, int numsSize) {
    IntArrayList* list = CreateIntArrayList(numsSize);
 for (int i = 0; i < numsSize; i++) {
	if (!AddIntArrayList(list, nums[i])) {
		fprintf(stderr, "Failed to add element %d\n", nums[i]);
		FreeIntArrayList(list);
		return;
	}
 }
 SortIntArrayList(list, compareFunZeroToLast);
 for (int i = 0; i < numsSize; i++) {
	nums[i] = GetIntArrayList(list, i);
 }
}

结果:

ok,性能稍差而已。

想起来忘记释放内存了,内存管理是真烦人哪, moveZeroes函数重新贴一下代码:

void moveZeroes(int* nums, int numsSize) { // LeeCode283. 移动零
	IntArrayList* list = CreateIntArrayList(numsSize);
	for (int i = 0; i < numsSize; i++) {
		if (!AddIntArrayList(list, nums[i])) {
			fprintf(stderr, "Failed to add element %d\n", nums[i]);
			FreeIntArrayList(list);
			return;
		}
	}
	SortIntArrayList(list, compareFunZeroToLast);
	for (int i = 0; i < numsSize; i++) {
		nums[i] = GetIntArrayList(list, i);
	}
	FreeIntArrayList(list); // 别忘记释放内存!
}

总结,编码中遇过好几个错误。 1、 函数不要返回局部指针变量,局部指针变量,存储在 ‌栈内存‌ ,若该地址在函数退出后会被回收,导致出现野指针。必须使用 malloc 在堆上分配内存。  2、若c、c++混合编程,头文件需要加跨语言支持。 3、记得释放内存 

相关文章:

  • RuBii,基于人工智能的二次元角色创作平台
  • MySQL 的索引
  • 《深入探索 Python 数据分析:用 Pandas 高效处理与可视化大型数据集》
  • 搭建QNX Software Center的Docker环境
  • AIGC(生成式AI)试用 28 -- 跟着清华教程学习 - AIGC发展研究 3.0
  • 整合分块请求大模型返回的测试用例及小工具显示bug修复
  • 新手小白如何使用docsify本地搭建一个文档网站并一键发布公网
  • Vue 项目安装依赖报错:errno -4048
  • 线性表入门
  • 【蓝桥杯14天冲刺课题单】Day3
  • Day 09
  • Qwt入门
  • STC89C52单片机学习——第38节: [17-2] 红外遥控红外遥控电机
  • LangChain4j 入门(二)
  • 分治-归并系列一>数组中的逆序对
  • Linux的异常修复机制__ex_table主要作用
  • 全球地理数据库 GeoNames
  • Android Framework 层 Hook 技术详解
  • 内网渗透(DMZ--->DC)
  • 监控易一体化运维:资产管理,企业资产的智能管家