-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.c
154 lines (129 loc) · 4.96 KB
/
test.c
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
c and c++ solutions. c++ is O(n) time and just 6 lines. Includes c, O(n), hashmap solution
Language Author Votes
c ChrisTrompf 7
c++
C++ has all the nice tools to solve this quickly and easily.
Short and simple c++ solution. O(n) time, O(n) space
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map<int, std::size_t> tmp;
for (std::size_t i = 0; i < nums.size(); ++i) {
if (tmp.count(target - nums[i])) {
return {tmp[target - nums[i]], i};
}
tmp[nums[i]] = i;
}
return {nums.size(), nums.size()};
}
C does not have all the niceities of c++ and other language, so we have to do it the hard way.
Obvious brute force approach. O(n^2) time, O(1) space
int* twoSum(int* nums, int numsSize, int target) {
int* ret = (char*)malloc(2 * sizeof(int));
for (ret[0] = 0; ret[0] < numsSize; ++ret[0]) {
for (ret[1] = ret[0] + 1; ret[1] < numsSize; ++ret[1]) {
if (nums[ret[0]] + nums[ret[1]] == target) {
return ret;
}
}
}
return ret;
}
Sorting approach. O(nlogn) time, O(n) space
The brute force is obviously expensive. If we were able to instead have the numbers in sorted order, we can find a solution in O(n) time. The reasoning behind this is as follows;
Start with the two indexes, pointing to the lowest (lo) and highest (hi) values.
If current values are less than our target, then increase lo and hence increase the sum. If the sum is greater than our target, then decrease hi and hence reduce the sum.
Continue from 2. so long as the sum doesn’t equal the target.
The problem is of course that c makes us do it the hard way. In particular we don’t want to rearrange the nums array as we need to return the indexes. We have to provide our own functions. partition_indexes that reorders an array of indexes based on the value of nums that the indexes address and sort_indexes that uses quicksort to reorder the index mappings.
Even though finding the answer if the numbers are sorted is O(n), we have to pay O(nlogn) time for the sort, so the solution is O(nlogn) time.
void swap(int * const a, int * const b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
// Partition indexes that map to nums, without changing nums values or ordering
int partition_indexes(const int* const nums, int* const indexes, int lo, int hi) {
int pivot = lo++;
int pivot_val = nums[indexes[pivot]];
int idx = pivot;
int tmp;
for (; lo < hi; ++lo) {
if (nums[indexes[lo]] <= pivot_val) {
swap(indexes + lo, indexes + ++idx);
}
}
// Swapt the pivot (which is at the front) with the last value less or equal to the pivot
swap(indexes + pivot, indexes + idx);
return idx;
}
// Sort indexes that map to nums, without changing nums values or ordering
void sort_indexes(const int* const nums, int* const indexes, int lo, int hi) {
if (lo < hi) {
int pivot = partition_indexes(nums, indexes, lo, hi);
sort_indexes(nums, indexes, lo, pivot);
sort_indexes(nums, indexes, pivot + 1, hi);
}
}
int* twoSum(int* nums, int numsSize, int target) {
int* ret = (int*)malloc(2 * sizeof(int));
// Build index mapping to nums that is sorted assendingly
int* indexes = (int *)malloc(numsSize * sizeof(int));
for (int i = 0; i < numsSize; ++i) {
indexes[i] = i;
}
sort_indexes(nums, indexes, 0, numsSize);
// Move in from either side, if the pair is below target, then left index must increase
// to increase the sum, while right must decrease if the sum is over
int lo = 0;
int hi = numsSize - 1;
while (nums[indexes[lo]] + nums[indexes[hi]] != target) {
if (nums[indexes[lo]] + nums[indexes[hi]] < target) {
++lo;
} else {
--hi;
}
}
ret[0] = indexes[lo];
ret[1] = indexes[hi];
free(indexes);
return ret;
}
Hashmap. O(n) time, O(n) space
The hashmap solution for c++ is nice and simple, the c takes a bit more work and uses the external uthash (which is automatically included for c solutions).
struct number_hash {
int value;
int index;
UT_hash_handle hh;
};
void destroy_table(struct number_hash** table) {
struct number_hash* curr;
struct number_hash* tmp;
HASH_ITER(hh, *table, curr, tmp) {
HASH_DEL(*table, curr);
free(curr);
}
}
int* twoSum(int* nums, int numsSize, int target) {
struct number_hash* table = NULL;
struct number_hash* element;
int* ret = (int*) malloc(2 * sizeof(int));
int remaining;
for (int i = 0; i < numsSize; ++i) {
remaining = target - nums[i];
// Find if there has already been an element such that the sum is target
HASH_FIND_INT(table, &remaining, element);
if (element) {
ret[0] = element->index;
ret[1] = i;
break;
}
// Add the new number to the hash table if it doesn't exist already
HASH_FIND_INT(table, &nums[i], element);
if (!element) {
element = (struct number_hash *) malloc(sizeof(*element));
element->value = nums[i];
element->index = i;
HASH_ADD_INT(table, value, element);
}
}
destroy_table(&table);
return ret;
}