CS1010 Notes
  • Welcome
  • Lec/Tut/Lab/Exes
    • Lecture
      • Lec 01 - Computational Problem Solving
      • Lec 02 - Functions and Types
      • Lec 03 - Basic C Programming
      • Lec 04 - Conditionals
      • Lec 05 - Loops
      • Lec 06 - Call Stacks, Arrays
        • Diagnostic Quiz
      • Lec 07 - Pointers, Memory management
        • Diagnostic Quiz
      • Lec 08 - Multi-d Array, Efficiency
        • Diagnostic Quiz
      • Lec 09 - Searching and Sorting
        • Diagnostic Quiz
      • Lec 10 - More Recursion
        • Diagnostic Quiz
      • Lec 11 - Strcut & Standard I/O
        • Diagnostic Quiz
      • Lec 12 - Recap
    • Tutorial
      • Tut 01 - Computational Problem-Solving
      • Tut 02 - Functions and Conditionals
      • Tut 03 - More on Conditionals
      • Tut 04 - Loops
      • Tut 08 - Searching and Sorting
    • Lab
      • Lab 01 - Unix/Vim Setup
      • Lab 02 - Debugging
      • Lab 03 - Assert
      • Lab 04 - Test Cases
      • Lab 05 - Arrays
      • Lab 06 - Memory Errors
      • Lab 07 - Compiling with Clang
      • Lab 08 - C Preprocessor
      • Lab 09 - Backtracking
      • Lab 10 - Struct and Wrap up
    • Exercises
      • Exercise 3 - Fixed-Length Arrays
      • Exercise 4 - Dynamic Arrays and Strings
      • Exercise 6 - Searching and Sorting
      • Exercise 7 - More Recursion
      • Exercise 8 - Struct
  • Past Year Exam
    • Midterm PE
      • PE1 (AY18/19)
      • PE1 (AY20/21)
      • PE1 (AY21/22)
      • PE0 (AY22/23)
      • PE0 (AY23/24)
    • Midterm Paper
      • Midterm (AY18/19)
      • Midterm (AY20/21)
      • Midterm (AY21/22)
      • Midterm (AY22/23)
    • PE1 Review
      • PE1 (AY23/24)
    • PE2 Review
      • PE2 (AY18/19)
      • PE2 (AY20/21)
      • PE2 (AY21/22)
      • PE2 (AY22/23)
      • PE2 (AY23/24)
    • Final Paper
      • Final (AY18/19)
      • Final (AY20/21)
      • Final (AY21/22)
      • Final (AY22/23)
      • Final (AY23/24)
  • Current Year Exam
    • PE0 (AY24/25)
    • PE1 (AY24/25)
    • PE2 (AY24/25)
    • Final (AY24/25)
  • Toolbox
    • Vim & Unix
    • GDB
  • After CS1010
Powered by GitBook
On this page
  • Problems
  • 1. Transpose
  • 2. Palindrome
  • 3. Rotate*
  • 4. Marnell
  • 5. Bracket*
  • Tips
Edit on GitHub
  1. Past Year Exam
  2. PE2 Review

PE2 (AY18/19)

PreviousPE2 ReviewNextPE2 (AY20/21)

Last updated 6 months ago

Problems

Questions:

Official Answers:

1. Transpose

This question is a give-away question, the most important part is that m2[j][i] = m1[i][j].

2. Palindrome

A problem that uses technique.

Recursive Solution

bool palidrome(long start, long end, char *str)
{
  if (start >= end)
  {
    return true;
  }
  if (isalpha(str[start]) && isalpha(str[end]))
  {
    return (tolower(str[start]) == tolower(str[end])) && palidrome(start + 1, end - 1, str);
  }
  if (!isalpha(str[start]))
  {
    return palidrome(start + 1, end, str);
  }
  if (!isalpha(str[end]))
  {
    return palidrome(start, end - 1, str);
  }
  return palidrome(start + 1, end - 1, str);
}

Notice that this recursive solution cannot pass two cases since it will cause a stack overflow.

Iterative solution

bool palidrome_loop(long start, long end, char *str)
{
  while (start < end)
  {
    if (isalpha(str[start]) && isalpha(str[end]))
    {
      if (tolower(str[start]) != tolower(str[end]))
      {
        return false;
      }
      start += 1;
      end -= 1;
    }
    else if (!isalpha(str[start]))
    {
      start += 1;
    }
    else if (!isalpha(str[end]))
    {
      end -= 1;
    }
    else
    {
      start += 1;
      end -= 1;
    }
  }
  return true;
}

This iterative can pass all the test cases and it uses the sliding window technique to move the boundaries.

3. Rotate*

An awesome variant question of Binary Search

Instead of using the method in the comments, I used the idea of mapping. Before that, since we already know Binary Search needs the list to be sorted. In this question, the list is sorted but in a another way -- "rotated". For example, in the list below, the actual input position is shown in red, while the sorted position should be in blue.

The way to treat the list as sorted is to use the idea of offset. We still search from the middle, but the actual middle is not the red 3, but the blue 3. Suppose we want to search for number 4 (pos 6), we compare it with the actual middle number, which is 1 in pos 0(not 4 in pos 3). Then we find it is bigger, so we can be sure number 4 is at right of actual middle number 1.

One thing we can notice is that the offset is related to how many bits we have right rotated. The logic is below:

long within_range(long index, long rotate, size_t len)
{
  if ((index + rotate) >= (long)len)
  {
    return index + rotate - (long)len;
  }
  return index + rotate;
}

After knowing this, we can modify our Binary Search slightly to pass this question

long search(long *a, long i, long j, long q, size_t len)
{
  if (i > j)
  {
    return -1;
  }
  long rotate = rotate_pos(a, len);
  long mid = (i + j) / 2;
  long mid_rotated_pos = within_range(mid, rotate, len);
  if (a[mid_rotated_pos] == q)
  {
    return mid_rotated_pos;
  }
  if (a[mid_rotated_pos] > q)
  {
    return search(a, i, mid - 1, q, len);
  }
  return search(a, mid + 1, j, q, len);
}

4. Marnell

The idea given in the comments are pretty awesome! That is to combine the is_prime and is_semiprime together. This is done by if i is a factor of n and i is a prime, then if n/i is also a prime, then n is a semiprime.

long is_prime_or_semiprime(long n) {
    if (n <= 1) {
        return NEITHER;
    }
    for (long i = 2; i*i <= n; i += 1) {
        if (n % i == 0) {
            if (is_prime_or_semiprime(i) == PRIME && is_prime_or_semiprime(n/i) == PRIME) {
                return SEMIPRIME;
            }
            return NEITHER;
        }
    }
    return PRIME;
}

5. Bracket*

An awesome and hard problem about bracket matching. It is obvious to use stack to solve it. But here recursion is required, making it harder to think.

Instead of using the sliding window technique in 2. Palindrome, we mimic the idea of using stack to solve this problem, that is whether the "bracket" is consumed or not. Thus, the recursive function will return the index of the first unconsumed character.

The first two return blocks both returns the position that cannot be consumed. The Line 10 will return the solution for the subproblem, which is the string begins from end+1. The Line 12 will return the begin position if it cannot be consumed in the current function call.

long consume_valid(char *string, int begin) {
    if (string[begin] == '\0') {
        return begin;
    }
    if (!is_open(string[begin])) {
        return begin;
    }
    long end = consume_valid(string, begin+1);
    if (is_matching_close(string[begin], string[end])) {
        return consume_valid(string, end + 1);
    }
    return begin;
}

The tricky point is that in Line 8, you try to consume open bracket in the current function call.

The call in main() should be

long end = is_valid(str, 0);
if (str[end] == '\0') {
    cs1010_println_string("yes");
} else {
    cs1010_println_string("no");
}

Tips

  1. Include the is_prime() and count_factors() into the cheatsheet

A question that combines the is_prime() in , and the way to count all the prime factors of a num in .

Sliding Window
3. Goldbach*
4. Unique*
94KB
pe2-1819-s1.pdf
pdf
Questions
137KB
pe2-1819-s1-with-comments.pdf
pdf
Official Answers
Example