記錄一下如果 LeetCode 回傳值是二維陣列要怎麼處理
最近無聊寫了一些 LeetCode,在碰到題目要回傳二維陣列時有點卡關,不論怎麼寫都遇到
1
2
3
4
5
|
=================================================================
==32==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff01384c48 at pc 0x556b0238f4f1 bp 0x7fff01384910 sp 0x7fff01384900
READ of size 8 at 0x7fff01384c48 thread T0
#2 0x7efd505ac0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
... (後面一大串)
|
後來認真看了後才知道是沒有仔細看題目的註解,也對 C 語言一些機制不大了解。
static vs. dynamic array
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
int a[10];
printf("size of a is %lu\n", sizeof(a));
// size of b is 8
int *b;
b = malloc(sizeof(int) * 10);
printf("size of b is %lu\n", sizeof(b));
// size of b is 8
return 0;
}
|
靜態的陣列可以用 sizeof 來知道陣列的大小。
但動態宣告的陣列無法,如上面的範例,印出 b 的值是 8,表示 b 這個指向 int 的指標的大小。
所以如果有在 function 中新分配空間給動態陣列,並想把這個動態陣列傳到其他地方使用,除了這個動態陣列的本身 (也就是陣列的開始位置,以上面的例子來說是 b),還要讓呼叫的地方那邊知道你分配了多長的位子。
但 C 語言的 function 只能有一個回傳值。解決方法可以把這個動態陣列連同長度包成 struct,或是讓陣列長度的這個資訊透過 function arguments 的方式改動呼叫那邊的值。
好像寫的有點亂,來看下面的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
#include <stdio.h>
#include <stdlib.h>
int *createDynamicArray(int *arrayLength) {
*arrayLength = 5;
int *ret = calloc(sizeof(int), (*arrayLength));
return ret;
}
int main(int argc, char const *argv[])
{
int arrayLength;
int *arr;
arr = createDynamicArray(&arrayLength);
for(int i = 0; i < arrayLength; i++) {
printf("a[%d] = %d\n", i, arr[i]);
}
free(arr);
return 0;
}
|
我在 createDynamicArray 這個 function 中建立了一個動態陣列,想在 main 中用它。除了回傳這個動態陣列外,在 main 還會需要知道他的長度。在 main 中第 13 行宣告了他的長度,在 createDynamicArray 中以它作為 function argument,第 6 行修改了他的值。因此在 main 中可以操作這個陣列。
LeetCode 429. N-ary Tree Level Order Traversal (Medium)
那時候我是在寫 https://leetcode.com/problems/n-ary-tree-level-order-traversal/
簡單來說要回傳一個二維陣列,但呼叫那邊不知道這個陣列的長寬,所以這個陣列的長相也要讓呼叫端知道。
1
2
3
4
5
6
7
8
9
|
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
int** levelOrder(struct Node* root, int* returnSize, int** returnColumnSizes) {
}
|
題目其實很清的寫了回傳的陣列高是 *returnSize,而每個 col 的大小則是存在 *returnColumnSizes 中。
在 main function 中,returnSize 是 int,而 returnColumnSizes 是 int *,但因為我想在 function 中更改他們的值,所以各自都多了一顆 *,變成 int * 和 int **。
一開始沒仔細看說明,以為一個長度為 3,各 colSize 為 [1,3,2] 的陣列只要回傳 [1,3,2],但沒有長度不行,而且想改一個整數指標的指向在 function 只用整數指標去接根本無法真的改動到,而是要用整數指標的指標。
這題我的完整 code 長這樣
main function 主要是展示了應該如何呼叫,在 submit 時不能交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
#include <stdlib.h>
struct Node {
int val;
int numChildren;
struct Node** children;
};
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
void findDepth(struct Node* root, int *depth, int curDepth) {
if(root->numChildren == 0) {
*depth = (curDepth > *depth ? curDepth : *depth);
}
else {
for(int i = 0; i < root->numChildren; i++) {
findDepth(root->children[i], depth, curDepth+1);
}
}
}
void findNodeNumEachLevel(struct Node* root, int** returnColumnSizes, int level) {
if(!root) {
return;
}
else {
(*returnColumnSizes)[level] ++;
for(int i = 0; i < root->numChildren; i++) {
findNodeNumEachLevel(root->children[i], returnColumnSizes, level+1);
}
}
}
void levelOderTraverse(struct Node* root, int **ans, int** returnColumnSizes, int level, int **levelCurPos) {
if(!root) {
return;
}
else {
ans[level][(*levelCurPos)[level]] = root->val;
(*levelCurPos)[level]++;
for(int i = 0; i < root->numChildren; i++) {
levelOderTraverse(root->children[i], ans, returnColumnSizes, level+1, levelCurPos);
}
}
}
int** levelOrder(struct Node* root, int* returnSize, int** returnColumnSizes) {
//***********************************************************************//
// Deals with the case of empty tree.
if(!root) {
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
//***********************************************************************//
// Step 1. Get the depth of the tree.
// i.e. Obtain the value of returnSize.
int depth = 0;
findDepth(root, &depth, 1);
*returnSize = depth;
//***********************************************************************//
// Step 2. Get the number of nodes of each level.
// i.e. Decide the value of returnColumnSizes array.
*returnColumnSizes = malloc(sizeof(int*) * depth);
for(int i = 0; i < depth; i++) {
(*returnColumnSizes)[i] = 0;
}
findNodeNumEachLevel(root, returnColumnSizes, 0);
//***********************************************************************//
// Step 3. Fill in the result 2d array by the correct value.
// Traverse the whole tree and fill the number to the correct
// position in the result 2d array.
int **result;
result = malloc(sizeof(int*) * depth);
for(int i = 0; i < depth; i++) {
result[i] = malloc(sizeof(int) * (*returnColumnSizes)[i]);
}
int *levelCurPos = malloc(sizeof(int)*depth);
for(int i = 0; i < depth; i++) {
levelCurPos[i] = 0;
}
levelOderTraverse(root, result, returnColumnSizes, 0, &levelCurPos);
free(levelCurPos);
return result;
}
int main() {
int returnSize;
int *returnColumnSizes;
levelOrder(0, &returnSize, &returnColumnSizes);
return 0;
}
|