本篇博客会讲解力扣“2418. 按身高排序”的解题思路,这是题目链接。
想要排序身高数组是非常简单的。我们在对身高数组进行排序时,会进行一些操作,比如交换2个元素等等。本题中,相当于我们要“记住”排序身高数组中进行了哪些操作,对名字数组进行同样的操作。应该如何进行呢?
一种简单的想法是:可以把2个数组进行某种形式的“绑定”。一开始,2个数组相同下标的元素是一一对应的关系,一个名字对应着一个身高,我们可以把名字和身高绑定在一块,对身高排序的同时也对名字排序,这样就实现了题目要求的效果。
具体的“绑定”方法,我们可以使用结构体绑定,也可以使用二维数组来绑定。
方法1
最简单的想法是使用结构体来绑定。使用结构体,把名字和身高绑定起来,排序结构体数组,再回写名字即可。需要注意的是,为防止内存泄漏,结构体数组最后是需要释放的,如果直接让返回数组的元素存储结构体数组中元素对应名字的地址,就会出现野指针错误。所以正确的做法是,开辟一块新空间用来存储字符串,并使用strcpy函数把字符串从结构体数组中拷贝到返回数组中。
#define NAME_LENGTH_MAX 20typedef struct PeoInfo
{char* name;int height;
}PeoInfo;int CmpByHeight(const void* p1, const void* p2)
{return ((PeoInfo*)p2)->height - ((PeoInfo*)p1)->height;
}char ** sortPeople(char ** names, int namesSize, int* heights, int heightsSize, int* returnSize){// 创建结构体数组PeoInfo* info = (PeoInfo*)malloc(sizeof(PeoInfo) * namesSize);for (int i = 0; i < namesSize; ++i){info[i].name = names[i];info[i].height = heights[i];}// 排序结构体数组qsort(info, namesSize, sizeof(PeoInfo), CmpByHeight);// 回写身高信息char** ret = (char**)malloc(sizeof(char*) * namesSize);*returnSize = namesSize;for (int i = 0; i < namesSize; ++i){ret[i] = (char*)malloc(sizeof(char) * (NAME_LENGTH_MAX + 1));strcpy(ret[i], info[i].name);}free(info);info = NULL;return ret;
}
方法2
由于数组中的元素都是相同类型的,我们想要排序的身高数组的元素是int类型的,而下标也是int类型的,所以可以使用二维数组把身高和对应位置的下标绑定起来。具体的,可以创建一个size行2列的二维数组,第一列存储身高,第二列存储对应的下标,排序时对行进行排序,这样身高排序成功的同时,也记住了原始的下标,这样就能通过原始的下标找到一开始对应的名字了。这种解法较为巧妙,因为二维数组作为栈上的元素,在出作用域后会被销毁,但是不影响返回数组,这是由于返回数组里存储的是原名字数组中元素的地址,而在oj里,所有传递的形式参数都是在堆上开辟的,函数返回后并不会销毁,所以这么实现是可行的。
// 比较指针指向的第一个整数
int cmp(const void* p1, const void* p2)
{return *(int*)p2 - *(int*)p1;
}char ** sortPeople(char ** names, int namesSize, int* heights, int heightsSize, int* returnSize){// 把原下标和对应身高绑定int heighti[heightsSize][2];for (int i = 0; i < heightsSize; ++i){heighti[i][0] = heights[i];heighti[i][1] = i;}// 对二维数组的每一行排序qsort(heighti, heightsSize, sizeof(heighti[0]), cmp);// 根据排序后的二维数组,把对应下标的名字写回新数组char** ret = (char**)malloc(sizeof(char*) * namesSize);*returnSize = namesSize;for (int i = 0; i < namesSize; ++i){ret[i] = names[heighti[i][1]];}return ret;
}
总结
2种绑定的思路:一种思路是使用结构体直接把名字和身高绑定,另一种思路是使用二维数组把身高和对应下标绑定。回写时根据绑定的思路,选择是直接回写还是通过下标找到对应元素再回写。
感谢大家的阅读!