Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,33 @@ public SimpleDictionaryTest() {
@Test
public void testIsWordNullDict() {
System.out.println("isWord Null dictionary");
String w = "";
SimpleDictionary instance = new SimpleDictionary(null);
boolean expResult = false;
boolean result = instance.isWord(w);
assertEquals(expResult, result);
assertEquals(false, (new SimpleDictionary(null)).isWord(""));
}

@Test
public void testIsPrefixNullDict() {
System.out.println("isPrefix Null dictionary");
String p = "";
SimpleDictionary instance = new SimpleDictionary(null);
boolean expResult = false;
boolean result = instance.isPrefix(p);
assertEquals(expResult, result);
assertEquals(false, new SimpleDictionary(null).isPrefix(""));
}

@Test
public void testIsWordEmptyDict() {
System.out.println("isWord Empty dictionary");
String w = "";
String[] dict = new String[0];
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = false;
boolean result = instance.isWord(w);
assertEquals(expResult, result);
assertEquals(false, new SimpleDictionary(new String[0]).isWord(""));
}

@Test
public void testIsPrefixEmptyDict() {
System.out.println("isPrefix Empty dictionary");
String p = "";
String[] dict = new String[0];
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = false;
boolean result = instance.isPrefix(p);
assertEquals(expResult, result);
assertEquals(false, new SimpleDictionary(new String[0]).isPrefix(""));
}

@Test
public void testIsWordSingleWordDict_F() {
System.out.println("isWord SingleWord dictionary (F)");
String w = "";
String[] dict = new String[1];
dict[0] = "cat";
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = false;
boolean result = instance.isWord(w);
assertEquals(expResult, result);
assertEquals(false, new SimpleDictionary(dict).isWord(""));
}

@Test
Expand All @@ -81,17 +59,16 @@ public void testIsPrefixSingleWordDict_F() {
String[] dict = new String[1];
dict[0] = "cat";
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = false;
boolean result1 = instance.isPrefix(p1);
boolean result2 = instance.isPrefix(p2);
boolean result3 = instance.isPrefix(p3);
boolean result4 = instance.isPrefix(p4);
boolean result5 = instance.isPrefix(p5);
assertEquals(expResult, result1);
assertEquals(expResult, result2);
assertEquals(expResult, result3);
assertEquals(expResult, result4);
assertEquals(expResult, result5);
assertEquals(false, result1);
assertEquals(false, result2);
assertEquals(false, result3);
assertEquals(false, result4);
assertEquals(false, result5);
}

@Test
Expand All @@ -101,9 +78,8 @@ public void testIsWordSingleWordDict_T() {
String[] dict = new String[1];
dict[0] = "cat";
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = true;
boolean result = instance.isWord(w);
assertEquals(expResult, result);
assertEquals(true, result);
}
@Test
public void testIsPrefixSingleWordDict_T() {
Expand All @@ -115,15 +91,14 @@ public void testIsPrefixSingleWordDict_T() {
String[] dict = new String[1];
dict[0] = "cat";
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = true;
boolean result1 = instance.isPrefix(p1);
boolean result2 = instance.isPrefix(p2);
boolean result3 = instance.isPrefix(p3);
boolean result4 = instance.isPrefix(p4);
assertEquals(expResult, result1);
assertEquals(expResult, result2);
assertEquals(expResult, result3);
assertEquals(expResult, result4);
assertEquals(true, result1);
assertEquals(true, result2);
assertEquals(true, result3);
assertEquals(true, result4);
}

@Test
Expand All @@ -132,9 +107,8 @@ public void testIsWordSmallDict_F() {
String w = "AT";
String[] dict = {"CAR", "CARD", "CART", "CAT"};
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = false;
boolean result = instance.isWord(w);
assertEquals(expResult, result);
assertEquals(false, result);
}

@Test
Expand All @@ -144,11 +118,10 @@ public void testIsPrefixSmallDict_F() {
String p2 = "PAR";
String[] dict = {"CAR", "CARD", "CART", "CAT"};
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = false;
boolean result1 = instance.isPrefix(p1);
boolean result2 = instance.isPrefix(p2);
assertEquals(expResult, result1);
assertEquals(expResult, result2);
assertEquals(false, result1);
assertEquals(false, result2);
}

@Test
Expand All @@ -159,13 +132,12 @@ public void testIsWordSmallDict_T() {
String w3 = "CAT";
String[] dict = {"CAR", "CARD", "CART", "CAT"};
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = true;
boolean result1 = instance.isWord(w1);
boolean result2 = instance.isWord(w2);
boolean result3 = instance.isWord(w3);
assertEquals(expResult, result1);
assertEquals(expResult, result2);
assertEquals(expResult, result3);
assertEquals(true, result1);
assertEquals(true, result2);
assertEquals(true, result3);
}

@Test
Expand All @@ -175,10 +147,9 @@ public void testIsPrefixSmallDict_T() {
String p2 = "CAR";
String[] dict = {"CAR", "CARD", "CART", "CAT"};
SimpleDictionary instance = new SimpleDictionary(dict);
boolean expResult = true;
boolean result1 = instance.isPrefix(p1);
boolean result2 = instance.isPrefix(p2);
assertEquals(expResult, result1);
assertEquals(expResult, result2);
assertEquals(true, result1);
assertEquals(true, result2);
}
}
37 changes: 21 additions & 16 deletions CodeU_Assignement_5/src/codeu_assignement_5/KemUnknownLanguage.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,24 @@ public class KemUnknownLanguage {
* Output: alphabet (an ordered list of characters) of that language, letters we cannot decide are appended in the end.
*/
public List<Character> getAlphabeit(String[] alienWords) {
if (alienWords == null) {
return null;
}

List<Character> alphabet = null;
if ((alienWords != null) && (alienWords.length > 0)) {
/* Get the current order by prefix size, starting from 0 */
alphabet = getBasicAlphaBeit(alienWords, 0); /* Basic Alphabeit */
/* A,R,C from the example! */

/* Add from prefix while there are letters after first letter of prefix */
addToDictByPrefixSize(alienWords, alphabet);
/* Get the current order by prefix size, starting from 0 */
alphabet = inferAlphabetFromCommonPrefix(alienWords, 0); /* Basic Alphabeit */
/* A,R,C from the example! */

/* Add all the chars we cannot decide in the end - According to the comments in Slack */
for (String w : alienWords) {
for (Character c: w.toCharArray()) {
if (!alphabet.contains(c)) {
alphabet.add(c);
}
/* Add from prefix while there are letters after first letter of prefix */
addToDictByPrefixSize(alienWords, alphabet);

/* Add all the chars we cannot decide in the end - According to the comments in Slack */
for (String w : alienWords) {
for (Character c: w.toCharArray()) {
if (!alphabet.contains(c)) {
alphabet.add(c);
}
}
}
Expand All @@ -38,10 +41,12 @@ public List<Character> getAlphabeit(String[] alienWords) {
/*
* Inputs: All words with the same prefix (all the first prefixSize chars are the same!)
* Output: Per common prefix, gets the order of the chars
*
* Note: Assume the input is valid here!
*
* Process: Given an array of words that all match up to a common prefix length, infer an
* alphabetical ordering of the characters based on the order of the first differing character.
* No check is made that the common prefix really is the same across the list.
*/
private List<Character> getBasicAlphaBeit(String[] words, int prefixSize) {
private List<Character> inferAlphabetFromCommonPrefix(String[] words, int prefixSize) {
List<Character> ret = new ArrayList();
for (String w : words) {
if ((w.length() > prefixSize) && (!ret.contains(w.charAt(prefixSize)))) {
Expand Down Expand Up @@ -129,7 +134,7 @@ private void addToDictByPrefixSize(String[] alienWords, List<Character> alphabet
int prefixSize = j;
String[] sublistWords = getWordsWithSamePrefix(alienWords, i, prefixSize);
if (sublistWords.length > 1) {
List<Character> tempDict = getBasicAlphaBeit(sublistWords, prefixSize);
List<Character> tempDict = inferAlphabetFromCommonPrefix(sublistWords, prefixSize);
if (!tempDict.isEmpty()) {
mergeDict(alphabet,tempDict);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package codeu_assignement_5;

import java.util.ArrayList;
import java.util.Arrays;
import org.junit.Test;
import static org.junit.Assert.*;
Expand All @@ -24,7 +25,7 @@ public void testGetAlphabeitNullSet()
public void testGetAlphabeitEmptySet() {
System.out.println("getAlphabeit empty set of words");
KemUnknownLanguage instance = new KemUnknownLanguage();
assertEquals(null, instance.getAlphabeit(new String[0]));
assertEquals(new ArrayList(), instance.getAlphabeit(new String[0]));
}

@Test
Expand Down
129 changes: 129 additions & 0 deletions CodeU_Assignment_6/src/codeu_assignment_6/KemRearrangingCars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package codeu_assignment_6;

import java.util.ArrayList;
import java.util.Arrays;
import javafx.util.Pair;

/**
*
* @author Karine
*/
public class KemRearrangingCars {

/**
* Inputs: two arrays, each with a permutation of the numbers 0 to N,
* where permutationA is the current parking lot state, and permutationB is
* the desired parking lot state.
*
* Output: A series of moves, which leads from permutationA to permutationB
*
* Process:
*
* Time Complexity: O(n)
* Memory Compelxity: O(n)
* (2 arrays of size n + and array of steps size (n-1) max.)
*
* @param permutationA
* @param permutationB
* @return The return value is pairs of moves ordered from 0 to size of the array,
* from where the item was to the free location.
*/
public ArrayList<Pair<Integer,Integer>> getMovesRearrangingCars(Integer[] permutationA, Integer[] permutationB) {
if (!isValidInput(permutationA,permutationB)) {
return null;
}

ArrayList<Pair<Integer,Integer>> moveSeries = new ArrayList<>();
Integer[] lotCurrState = Arrays.copyOf(permutationA, permutationA.length); /* Deep copy */
int n = lotCurrState.length;

/* Say we wish to swap 3 with 0 (as in the example), we need to find 3
We keep the indeces of each element to so in O(1) - we update these
indeces till the end of the algorithm to keep the performance
*/ // 1,2,0,3 => 2,0,1,3
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Plural of "index" is "indices" ("indexes" also acceptable).

When creating a table like this, a "reverse mapping" (or inverse mapping) is the term most people use - putting that in the comment will help many people understand more easily. Having said that, the comment is clear, and the example is very helpful.

Integer[] currIndexToElements = new Integer[n];
for (int i=0; i<n; i++) {
currIndexToElements[permutationA[i]] = i;
}

/* Only for the first time need to find where is the 0 */
int currZeroLocation = currIndexToElements[0];

/* Till lotCurrState is not equal to permutationB, max steps n-1 */
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"max steps n-1" is not terribly clear - iterating from 0 to n-1 is n steps. It might be that the maximum number of swap steps is actually n-1 because each swap involves two numbers, or something like that, but just leaving "n-1" without justification is not very helpful, as you're forcing readers to think more than is necessary (we want the code to be clearly correct to the reader without hard work!).

You could just say something like - "single pass through array, O(n)", which gets across what we really care about.

for (int i=0; i<n; i++) {
if (lotCurrState[i] != permutationB[i]){
/* If location is not free, move the item there */
currZeroLocation = swap(lotCurrState[i], currZeroLocation, currIndexToElements, lotCurrState, moveSeries);

/* swap the right item into location i (excpet in the case of 0) */
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

excpet -> except

currZeroLocation = swap(permutationB[currZeroLocation], currZeroLocation, currIndexToElements, lotCurrState, moveSeries);
}
}

/* The return value is pairs of moves ordered from 0 to size of the array */
return moveSeries;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, simple algorithm. I have couple of comments on swap, but overall, this is very simple and clean.

}

/**
* Return false if the input is invalid (null, not the same size...)
*
* If required, you may add here throw of exceptions
*/
private boolean isValidInput(Integer[] permutationA, Integer[] permutationB) {
if ((permutationA == null) || (permutationB == null)) {
return false;
}
if (permutationA.length != permutationB.length) {
return false;
}
for (int i=0;i<permutationA.length;i++) {
if (permutationA[i] >= permutationA.length) {
return false;
}
if (permutationB[i] >= permutationB.length) {
return false;
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's nice to have these validity checks here. If you're going to do this, I suggest making the checks a little stronger - for example, you check all the numbers are below the limit, but you don't check they're above zero, or that there aren't repeats.

For this problem, it's possible to define an "isValidInput" method that is precise - it returns true if and only if it's valid, and this method is just a bit weaker than that. As a general pattern, I recommend making your validation functions as precise as possible, and clearly document it if it's conservative one way or the other - this is particularly important when it affects security, which is more often than you'd expect when working on production systems.


return true;
}

/**
* Process: swap two items in location of the currToSwap and the free space
* @return the location of the free space after the swap
*/
private int swap(int currToSwap, int currZeroLocation,
Integer[] currIndexToElements, Integer[] lotCurrState, ArrayList<Pair<Integer,Integer>> moveSeries) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your code is written in a very functional style here - all the parameters "swap" needs are passed through, and there are no member variables. When it comes to this many parameters, you might want to bundle them up - put them as member variables on an object, and then this method becomes "swap(int currToSwap)" - all the other variables becoming member variables.

I may have given you advice to pass things explicitly before, so this may sound like contradictory advice. The issue is when you have lots of arguments, bundling them up in an object is useful, especially if they're all being used together. If you've got an algorithm that is more hierarchical in its call tree, with only some variables used in some places, and lots of temporary values being passed from one step to another, that's when explicitly passing values through separate parameters is cleaner, since it highlights the way the data flows through the algorithm. In this case, all the data is used every time you call swap, and swap is pretty much the core of the algorithm, so it's less helpful.

if (currToSwap == 0) {
return currZeroLocation;
}

/* Find the location of the item to swap to current location */
int locationCurrToSwap = currIndexToElements[currToSwap];

/* Swap! */
lotCurrState[currZeroLocation] = currToSwap;
lotCurrState[locationCurrToSwap] = 0;

/* Update the output moves */
Pair<Integer,Integer> move = new Pair<>(locationCurrToSwap, currZeroLocation);
moveSeries.add(move);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could skip the creation of the intermediate variable, without losing any readability:

moveSeries.add(new Pair<>(locationCurrToSwap, currZeroLocation));


/* Update the indeces */
currIndexToElements[currToSwap] = currZeroLocation;
currIndexToElements[0] = locationCurrToSwap;

/* Will do out: currZeroLocation = locationCurrToSwap; */
return locationCurrToSwap;
}

public ArrayList<Pair<Integer,Integer>> getMovesRearrangingCarsAndPrint(Integer[] permutationA, Integer[] permutationB) {
ArrayList<Pair<Integer,Integer>> moves = getMovesRearrangingCars(permutationA, permutationB);

if (moves != null) {
moves.forEach(t->System.out.println("move from " + t.getKey() + " to " + t.getValue()));
}

return moves;
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice and simple algorithm. You can complete the task in fewer moves - closer to N than 2*N - so it might be worth having a quick think about that, but generally this is good, clean, simple code. Thank you.

Loading