Skip to content

Commit a2ec864

Browse files
committed
8/8/23 and 8/9/23
- convert_base.cc - replace_and_remove.cc - spreadsheet_encoding.cc - is_string_palindromic_punctuation.cc - reverse_words.cc - delete_from_list.cc - int_as_list_add.cc
1 parent e5f267c commit a2ec864

File tree

9 files changed

+322
-19
lines changed

9 files changed

+322
-19
lines changed

elements-of-programming-interviews/cpp/convert_base.cc

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,90 @@
1+
#include <cmath>
12
#include <string>
23

34
#include "test_framework/generic_test.h"
45
using std::string;
56

7+
/*
8+
- num can be between int max and min
9+
- int can be negative, and may have prefixes
10+
- 0 is valid in any base
11+
- b1, b2 are 2-16
12+
- converting bin string to dec int: multiply each digit by power of two, sum and
13+
return
14+
- converting dec int to bin string: left to right starting from closest pow of 2
15+
less than num: # set bit and subtract value.
16+
*/
17+
18+
#define ASCII_ZERO 48
19+
#define ASCII_A_LOWER 97
20+
#define ASCII_A_UPPER 65
21+
22+
int digitToInt(const char digit) {
23+
if ('0' <= digit && digit <= '9') {
24+
return digit - ASCII_ZERO;
25+
} else if ('A' <= digit && digit <= 'F') {
26+
return digit - ASCII_A_UPPER + 10;
27+
} else if ('a' <= digit && digit <= 'f') {
28+
return digit - ASCII_A_LOWER + 10;
29+
}
30+
return -1;
31+
}
32+
33+
char intToDigit(const int val) {
34+
if (0 <= val && val <= 9) {
35+
return val + ASCII_ZERO;
36+
} else if (0xA <= val && val <= 0xF) {
37+
return val - 10 + ASCII_A_UPPER;
38+
}
39+
return '!';
40+
}
41+
42+
int stringToInt(const string& val, int oldBase) {
43+
bool neg = val[0] == '-';
44+
int total = 0;
45+
int pow = 1;
46+
for (int i = val.size() - 1; i >= (neg ? 1 : 0); i--) {
47+
total += (digitToInt(val[i]) * pow);
48+
pow *= oldBase;
49+
}
50+
return total * (neg ? -1 : 1);
51+
}
52+
string intToString(int value, int newBase) {
53+
if (!value) {
54+
return "0";
55+
}
56+
bool neg = value < 0;
57+
value = abs(value);
58+
59+
string representation = neg ? "-" : "";
60+
long exp = 0;
61+
long sym = 1;
62+
while ((sym * long(pow(newBase, exp))) <= value) {
63+
exp++;
64+
}
65+
exp--;
66+
67+
while (value) {
68+
sym = newBase - 1;
69+
while ((sym * int(pow(newBase, exp))) > value && sym > 0) {
70+
sym--;
71+
}
72+
representation += intToDigit(sym);
73+
value -= (sym * int(pow(newBase, exp)));
74+
exp--;
75+
}
76+
while (exp >= 0) {
77+
representation += '0';
78+
exp--;
79+
}
80+
81+
return representation;
82+
}
83+
684
string ConvertBase(const string& num_as_string, int b1, int b2) {
7-
// TODO - you fill in here.
8-
return "";
85+
int base10Val = stringToInt(num_as_string, b1);
86+
string newVal = intToString(base10Val, b2);
87+
return newVal;
988
}
1089

1190
int main(int argc, char* argv[]) {

elements-of-programming-interviews/cpp/delete_from_list.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
#include "test_framework/timed_executor.h"
66
using std::shared_ptr;
77

8+
// If not tail, then the next node might be the tail,
9+
// so node.next == null.
10+
811
// Delete the node past this one. Assume node is not a tail.
912
void DeleteAfter(const shared_ptr<ListNode<int>>& node) {
10-
// TODO - you fill in here.
13+
shared_ptr<ListNode<int>> deleteMe = node->next;
14+
node->next = node->next->next;
1115
return;
1216
}
1317
shared_ptr<ListNode<int>> DeleteFromListWrapper(

elements-of-programming-interviews/cpp/int_as_list_add.cc

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
11
#include "list_node.h"
22
#include "test_framework/generic_test.h"
33

4+
/*
5+
- keep place, iterate through, (digit + digit) * place
6+
- need carry if adding node by node.
7+
- negatives? can handle by reading both to ints first then adding
8+
- no empty list
9+
*/
10+
411
shared_ptr<ListNode<int>> AddTwoNumbers(shared_ptr<ListNode<int>> L1,
512
shared_ptr<ListNode<int>> L2) {
6-
// TODO - you fill in here.
7-
return nullptr;
13+
int carry = 0;
14+
int total = 0;
15+
shared_ptr<ListNode<int>> current = make_shared<ListNode<int>>();
16+
shared_ptr<ListNode<int>> head = current;
17+
while (L1 || L2 || carry) {
18+
int val1 = (L1 != nullptr) ? L1->data : 0;
19+
int val2 = (L2 != nullptr) ? L2->data : 0;
20+
L1 = (L1 == nullptr) ? nullptr : L1->next;
21+
L2 = (L2 == nullptr) ? nullptr : L2->next;
22+
23+
// Assuming no negatives.
24+
total = (val1 + val2 + carry) % 10;
25+
carry = (val1 + val2 + carry >= 10) ? 1 : 0;
26+
27+
current->next = make_shared<ListNode<int>>();
28+
current->next->data = total;
29+
current = current->next;
30+
}
31+
return head->next;
832
}
933

1034
int main(int argc, char* argv[]) {

elements-of-programming-interviews/cpp/is_string_palindromic_punctuation.cc

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,46 @@
22

33
#include "test_framework/generic_test.h"
44
using std::string;
5+
6+
/*
7+
- two pointer palindrome test
8+
- Can contain non-alphanumerics, spaces, etc. Can use isalnum
9+
- possibly empty
10+
- need to compare lowercase to lowercase for alphas, tolower()
11+
- edge cases:
12+
- empty
13+
- 11111111 (is palindrome)
14+
- 11111aa (is not palindrome)
15+
- !!!!!aa is palindrome
16+
*/
17+
518
bool IsPalindrome(const string& s) {
6-
// TODO - you fill in here.
19+
if (s.empty()) {
20+
return true;
21+
}
22+
23+
int l = 0, r = s.size() - 1;
24+
while (l < r) {
25+
// Find next suitable lefts and rights
26+
if (!isalnum(s[l])) {
27+
l++;
28+
continue;
29+
}
30+
if (!isalnum(s[r])) {
31+
r--;
32+
continue;
33+
}
34+
35+
char left = s[l], right = s[r];
36+
// left is a digit and the other isn't / vice versa.
37+
if ((isdigit(left) != isdigit(right)) ||
38+
// tolower() returns the arg if no lowercase is available, works for
39+
// digits.
40+
(tolower(left) != tolower(right))) {
41+
return false;
42+
}
43+
l++, r--;
44+
}
745
return true;
846
}
947

elements-of-programming-interviews/cpp/replace_and_remove.cc

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,92 @@
77
using std::string;
88
using std::vector;
99

10+
/*
11+
- Replace every `a` with `d d`.
12+
- Delete every b.
13+
- Can assume s has enough space for final result
14+
- Do not need to worry about values beyond size (e.g. array[0] to array[size]
15+
must be represented in the final array)
16+
- If we process it backwards, the dd overwrites will only overwrite chars we've
17+
seen already. We know where it ends (or we can figure it out)
18+
---
19+
Trivial (o(n) on time and space): produce correct array, overwrite everything in
20+
original
21+
22+
Cases:
23+
- empty
24+
- No replace (efgh)
25+
- all replace (aaaaaaaa)
26+
- all delete (bbbb)
27+
*/
28+
29+
int ReplaceAndRemoveBruteForce(int size, char s[]) {
30+
vector<char> processed;
31+
for (int i = 0; i < size; i++) {
32+
switch (s[i]) {
33+
case 'b':
34+
break;
35+
case 'a':
36+
processed.push_back('d');
37+
processed.push_back('d');
38+
break;
39+
default:
40+
processed.push_back(s[i]);
41+
break;
42+
}
43+
}
44+
for (int i = 0; i < processed.size(); i++) {
45+
s[i] = processed[i];
46+
}
47+
return processed.size();
48+
}
49+
50+
int calculateFinalSize(int size, char s[]) {
51+
int finalSize = 0;
52+
for (int i = 0; i < size; i++) {
53+
switch (s[i]) {
54+
case 'b':
55+
break;
56+
case 'a':
57+
finalSize += 2;
58+
break;
59+
default:
60+
finalSize++;
61+
break;
62+
}
63+
}
64+
return finalSize;
65+
}
66+
67+
int removeB(int size, char s[]) {
68+
int j = 0;
69+
for (int i = 0; i < size; i++) {
70+
if (s[i] == 'b') {
71+
continue;
72+
}
73+
s[j++] = s[i];
74+
}
75+
return j;
76+
}
77+
78+
void replaceA(int size, int finalSize, char s[]) {
79+
for (int i = finalSize - 1, j = size - 1; j >= 0; j--) {
80+
if (s[j] == 'a') {
81+
s[i--] = 'd';
82+
s[i--] = 'd';
83+
} else {
84+
s[i--] = s[j];
85+
}
86+
}
87+
}
88+
1089
int ReplaceAndRemove(int size, char s[]) {
11-
// TODO - you fill in here.
12-
return 0;
90+
int finalSize = calculateFinalSize(size, s);
91+
int newEnd = removeB(size, s);
92+
replaceA(newEnd, finalSize, s);
93+
return finalSize;
1394
}
95+
1496
vector<string> ReplaceAndRemoveWrapper(TimedExecutor& executor, int size,
1597
const vector<string>& s) {
1698
std::vector<char> s_copy(s.size(), '\0');

elements-of-programming-interviews/cpp/reverse_words.cc

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,57 @@
11
#include <string>
2+
#include <vector>
23

34
#include "test_framework/generic_test.h"
45
#include "test_framework/timed_executor.h"
6+
using std::pair;
57
using std::string;
8+
using std::vector;
9+
10+
/*
11+
- Create an array of indexes and lengths, one for each word.
12+
- Reverse the array
13+
- Copy into a new string, then overwrite old
14+
- Time: O(n): each step (array creation, reversal, copying, overwriting) is
15+
linear
16+
- Takes n space for array of pairs, and n extra space for new string
17+
18+
- Happy cases:
19+
"bob talks to alice" -> "alice to talks bob"
20+
- Edge cases:
21+
- Empty string
22+
- String contains one word ("aaaaaaa")
23+
- Assuming words are delimited by whitespaces; don't actually know
24+
- What if there are multiple whitespaces between words? Assume not a case.
25+
26+
Then just reverse this list and copy it into a string.
27+
-----
28+
Better: mark where words are in the string. Reverse the string, then reverse
29+
each word.
30+
*/
31+
32+
vector<int> markSpaces(const string& s) {
33+
vector<int> spaceIdx;
34+
for (int i = 0; i < s.size(); i++) {
35+
if (s[i] == ' ') {
36+
spaceIdx.push_back(i);
37+
}
38+
}
39+
spaceIdx.push_back(s.size());
40+
return spaceIdx;
41+
}
642

743
void ReverseWords(string* s) {
8-
// TODO - you fill in here.
9-
return;
44+
string& sentence = *s;
45+
reverse(sentence.begin(), sentence.end());
46+
vector<int> spaces = markSpaces(sentence);
47+
int left = 0;
48+
for (int i = 0; i < spaces.size(); i++) {
49+
int right = spaces[i];
50+
reverse(sentence.begin() + left, sentence.begin() + right);
51+
left = spaces[i] + 1;
52+
}
1053
}
54+
1155
string ReverseWordsWrapper(TimedExecutor& executor, string s) {
1256
string s_copy = s;
1357

@@ -17,6 +61,7 @@ string ReverseWordsWrapper(TimedExecutor& executor, string s) {
1761
}
1862

1963
int main(int argc, char* argv[]) {
64+
/**/
2065
std::vector<std::string> args{argv + 1, argv + argc};
2166
std::vector<std::string> param_names{"executor", "s"};
2267
return GenericTestMain(args, "reverse_words.cc", "reverse_words.tsv",

elements-of-programming-interviews/cpp/spreadsheet_encoding.cc

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
1+
#include <cmath>
12
#include <string>
23

34
#include "test_framework/generic_test.h"
45
using std::string;
56

7+
/*
8+
A-Z = 1 to 26
9+
AA = 27
10+
ZZ = 702
11+
12+
- Not considering empty str
13+
- This is a different kind of base 26; rightmost column is mod 26, next is mod
14+
26*26.
15+
- A to ZZ inclusive is 702 (26*26 + 26)
16+
*/
17+
18+
#define ASCII_A 64 // so A = 1
19+
20+
int SSDecodeColIDWithExp(const string& col) {
21+
int total = 0;
22+
int exp = 0;
23+
for (auto it = col.rbegin(); it != col.rend(); it++, exp++) {
24+
total += ((*it - ASCII_A) * pow(26, exp));
25+
}
26+
return total;
27+
}
28+
629
int SSDecodeColID(const string& col) {
7-
// TODO - you fill in here.
8-
return 0;
30+
int total = 0;
31+
for (auto it = col.begin(); it != col.end(); it++) {
32+
total = (total * 26) + *it - 'A' + 1;
33+
}
34+
return total;
935
}
1036

1137
int main(int argc, char* argv[]) {

0 commit comments

Comments
 (0)