First Commit
commit
1c1f5dbd17
|
@ -0,0 +1,5 @@
|
||||||
|
Week*/*
|
||||||
|
!.gitignore
|
||||||
|
!Week*/src/
|
||||||
|
*.zip
|
||||||
|
*.jar
|
|
@ -0,0 +1,40 @@
|
||||||
|
import edu.princeton.cs.algs4.In;
|
||||||
|
import edu.princeton.cs.algs4.StdOut;
|
||||||
|
|
||||||
|
public class Outcast {
|
||||||
|
private WordNet word_net;
|
||||||
|
// constructor takes a WordNet object
|
||||||
|
public Outcast(WordNet wordnet){
|
||||||
|
word_net = wordnet;
|
||||||
|
}
|
||||||
|
// given an array of WordNet nouns, return an outcast
|
||||||
|
public String outcast(String[] nouns){
|
||||||
|
// For each element
|
||||||
|
// Sum the distance with all elements
|
||||||
|
// Update if the current distance is maximum
|
||||||
|
int max_dist = -1;
|
||||||
|
String outcast = "";
|
||||||
|
for(String noun : nouns){
|
||||||
|
int dist = 0;
|
||||||
|
for (String noun2 : nouns){
|
||||||
|
int d = word_net.distance(noun, noun2);
|
||||||
|
dist += d;
|
||||||
|
}
|
||||||
|
if (max_dist < 0 || dist > max_dist){
|
||||||
|
max_dist = dist;
|
||||||
|
outcast = noun;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outcast;
|
||||||
|
}
|
||||||
|
public static void main(String[] args){
|
||||||
|
|
||||||
|
WordNet wordnet = new WordNet(args[0], args[1]);
|
||||||
|
Outcast outcast = new Outcast(wordnet);
|
||||||
|
for (int t = 2; t < args.length; t++) {
|
||||||
|
In in = new In(args[t]);
|
||||||
|
String[] nouns = in.readAllStrings();
|
||||||
|
StdOut.println(args[t] + ": " + outcast.outcast(nouns));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
import edu.princeton.cs.algs4.Digraph;
|
||||||
|
import edu.princeton.cs.algs4.Queue;
|
||||||
|
import edu.princeton.cs.algs4.In;
|
||||||
|
//import edu.princeton.cs.algs4.StdIn;
|
||||||
|
import edu.princeton.cs.algs4.StdOut;
|
||||||
|
import edu.princeton.cs.algs4.SET;
|
||||||
|
|
||||||
|
|
||||||
|
public class SAP {
|
||||||
|
private Digraph G;
|
||||||
|
|
||||||
|
// constructor takes a digraph (not necessarily a DAG)
|
||||||
|
public SAP(Digraph G){
|
||||||
|
// Make a copy of the digraph
|
||||||
|
this.G = new Digraph(G);
|
||||||
|
}
|
||||||
|
|
||||||
|
// length of shortest ancestral path between v and w; -1 if no such path
|
||||||
|
public int length(int v, int w){
|
||||||
|
// This is the more straightforward implementation
|
||||||
|
int[] dist = new int[1];
|
||||||
|
ancestor(v, w, dist);
|
||||||
|
return dist[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// a common ancestor of v and w that participates in a shortest ancestral path; -1 if no such path
|
||||||
|
public int ancestor(int v, int w){
|
||||||
|
return ancestor(v, w, new int[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// length of shortest ancestral path between any vertex in v and any vertex in w; -1 if no such path
|
||||||
|
public int length(Iterable<Integer> v, Iterable<Integer> w){
|
||||||
|
if (v == null || w == null){
|
||||||
|
throw new IllegalArgumentException("Null input detected");
|
||||||
|
}
|
||||||
|
int[] shortest_dist = new int[]{-1};
|
||||||
|
ancestor(v, w, shortest_dist);
|
||||||
|
return shortest_dist[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// a common ancestor that participates in shortest ancestral path; -1 if no such path
|
||||||
|
public int ancestor(Iterable<Integer> v, Iterable<Integer> w){
|
||||||
|
if (v == null || w == null){
|
||||||
|
throw new IllegalArgumentException("Null input detected");
|
||||||
|
}
|
||||||
|
int[] shortest_dist = new int[]{-1};
|
||||||
|
return ancestor(v, w, shortest_dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ancestor(int v, int w, int[] distance){
|
||||||
|
// This private ancestor function return sca but also
|
||||||
|
// return by reference the distance
|
||||||
|
|
||||||
|
if (v<0 || w<0 || v>=G.V() || w>=G.V())
|
||||||
|
throw new IllegalArgumentException("Input values does not exist in graph");
|
||||||
|
|
||||||
|
if (v==w){
|
||||||
|
distance[0] = 0;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int shortest_dist = -1;
|
||||||
|
int sca = -1;
|
||||||
|
|
||||||
|
Queue<Integer> node_queue = new Queue<Integer>();
|
||||||
|
|
||||||
|
// First BFS
|
||||||
|
boolean[] firstMarked = new boolean[G.V()];
|
||||||
|
int[] firstDist = new int[G.V()];
|
||||||
|
node_queue.enqueue(v);
|
||||||
|
firstMarked[v] = true;
|
||||||
|
firstDist[v] = 0;
|
||||||
|
|
||||||
|
while(!node_queue.isEmpty()){
|
||||||
|
int a = node_queue.dequeue();
|
||||||
|
for (int b: G.adj(a)){
|
||||||
|
if (!firstMarked[b]){
|
||||||
|
node_queue.enqueue(b);
|
||||||
|
firstMarked[b] = true;
|
||||||
|
firstDist[b] = firstDist[a] + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second BFS
|
||||||
|
boolean[] secondMarked = new boolean[G.V()];
|
||||||
|
int[] secondDist = new int[G.V()];
|
||||||
|
node_queue.enqueue(w);
|
||||||
|
secondMarked[w] = true;
|
||||||
|
secondDist[w] = 0;
|
||||||
|
|
||||||
|
int current_dist = 0;
|
||||||
|
while(!node_queue.isEmpty()){
|
||||||
|
int a = node_queue.dequeue();
|
||||||
|
// Check for the distance to the common ancestor
|
||||||
|
// if reachable by the first one
|
||||||
|
if (firstMarked[a]){
|
||||||
|
current_dist = firstDist[a] + secondDist[a];
|
||||||
|
if (shortest_dist<0 || current_dist<shortest_dist){
|
||||||
|
shortest_dist = current_dist;
|
||||||
|
sca = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int b: G.adj(a)){
|
||||||
|
if (!secondMarked[b]){
|
||||||
|
node_queue.enqueue(b);
|
||||||
|
secondMarked[b] = true;
|
||||||
|
secondDist[b] = secondDist[a] + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
distance[0] = shortest_dist;
|
||||||
|
return sca;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ancestor(Iterable<Integer> v, Iterable<Integer> w, int[] distance){
|
||||||
|
/* This is a variant of the one-to-one version of ancestor
|
||||||
|
It is redundant to do BFS on each pair of integer
|
||||||
|
Rather, when given one-to-many
|
||||||
|
The amount of BFS should only be done once on each vertices
|
||||||
|
|
||||||
|
For sizes M and N (M being the minimum), Worst Case Growth rate:
|
||||||
|
Counting and Checking: M+N
|
||||||
|
First BFS: M * (E+V)
|
||||||
|
Second BFS: N *((E+V) + V*M) (Since everytime you explore a new node, you iterate across M)
|
||||||
|
Total: M + N + M * (E+V) + N * (E+V + V*M)
|
||||||
|
Or: (M+N)(E+V+1) + M*N*V
|
||||||
|
Compare to pairing: M*N*(2*(E+V)) => O(M*N*(E+V))
|
||||||
|
|
||||||
|
Extra memory used: M*V
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Counting and checking
|
||||||
|
int vSize = 0;
|
||||||
|
int wSize = 0;
|
||||||
|
for (Integer a : v){
|
||||||
|
if (a==null)
|
||||||
|
throw new IllegalArgumentException("Null value detected");
|
||||||
|
if (a<0 || a>=G.V())
|
||||||
|
throw new IllegalArgumentException("Input values does not exist in graph");
|
||||||
|
vSize++;
|
||||||
|
}
|
||||||
|
for (Integer a : w){
|
||||||
|
if (a==null)
|
||||||
|
throw new IllegalArgumentException("Null value detected");
|
||||||
|
if (a<0 || a>=G.V())
|
||||||
|
throw new IllegalArgumentException("Input values does not exist in graph");
|
||||||
|
wSize++;
|
||||||
|
}
|
||||||
|
// Determine which BFS to do first. Do it on the smaller set for lower memory
|
||||||
|
Iterable<Integer> first, second;
|
||||||
|
if (wSize < vSize){
|
||||||
|
first = w;
|
||||||
|
second = v;
|
||||||
|
}else{
|
||||||
|
first = v;
|
||||||
|
second = w;
|
||||||
|
}
|
||||||
|
int firstSize = Math.min(vSize, wSize);
|
||||||
|
|
||||||
|
|
||||||
|
int shortest_dist = -1;
|
||||||
|
int sca = -1;
|
||||||
|
int i = 0;
|
||||||
|
Queue<Integer> node_queue = new Queue<Integer>();
|
||||||
|
|
||||||
|
// First BFS on all first
|
||||||
|
boolean[][] firstMarked = new boolean[firstSize][G.V()];
|
||||||
|
int[][] firstDist = new int[firstSize][G.V()];
|
||||||
|
for(int start : first){
|
||||||
|
node_queue.enqueue(start);
|
||||||
|
firstMarked[i][start] = true;
|
||||||
|
firstDist[i][start] = 0;
|
||||||
|
|
||||||
|
while(!node_queue.isEmpty()){
|
||||||
|
int a = node_queue.dequeue();
|
||||||
|
for (int b: G.adj(a)){
|
||||||
|
if (!firstMarked[i][b]){
|
||||||
|
node_queue.enqueue(b);
|
||||||
|
firstMarked[i][b] = true;
|
||||||
|
firstDist[i][b] = firstDist[i][a] + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second BFS for all second
|
||||||
|
boolean[] secondMarked;
|
||||||
|
int[] secondDist;
|
||||||
|
|
||||||
|
for(int start : second){
|
||||||
|
secondMarked = new boolean[G.V()];
|
||||||
|
secondDist = new int[G.V()];
|
||||||
|
node_queue.enqueue(start);
|
||||||
|
secondMarked[start] = true;
|
||||||
|
secondDist[start] = 0;
|
||||||
|
|
||||||
|
int current_dist = 0;
|
||||||
|
while(!node_queue.isEmpty()){
|
||||||
|
int a = node_queue.dequeue();
|
||||||
|
// Check for the distance to the common ancestor
|
||||||
|
// if reachable by the first one
|
||||||
|
// For every node in the first
|
||||||
|
for(i=0;i<firstSize;i++){
|
||||||
|
if (firstMarked[i][a]){
|
||||||
|
current_dist = firstDist[i][a] + secondDist[a];
|
||||||
|
if (shortest_dist<0 || current_dist<shortest_dist){
|
||||||
|
shortest_dist = current_dist;
|
||||||
|
sca = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int b: G.adj(a)){
|
||||||
|
if (!secondMarked[b]){
|
||||||
|
node_queue.enqueue(b);
|
||||||
|
secondMarked[b] = true;
|
||||||
|
secondDist[b] = secondDist[a] + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
distance[0] = shortest_dist;
|
||||||
|
return sca;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do unit testing of this class
|
||||||
|
public static void main(String[] args){
|
||||||
|
In in = new In(args[0]);
|
||||||
|
Digraph G = new Digraph(in);
|
||||||
|
SAP sap = new SAP(G);
|
||||||
|
//while (!StdIn.isEmpty()) {
|
||||||
|
SET<Integer> v = new SET<Integer>();
|
||||||
|
v.add(1);
|
||||||
|
v.add(6);
|
||||||
|
SET<Integer> w = new SET<Integer>();
|
||||||
|
w.add(3);
|
||||||
|
int length = sap.length(v, w);
|
||||||
|
int ancestor = sap.ancestor(v, w);
|
||||||
|
StdOut.printf("length = %d, ancestor = %d\n", length, ancestor);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
import edu.princeton.cs.algs4.Digraph;
|
||||||
|
import edu.princeton.cs.algs4.In;
|
||||||
|
import edu.princeton.cs.algs4.RedBlackBST;
|
||||||
|
import edu.princeton.cs.algs4.Bag;
|
||||||
|
import edu.princeton.cs.algs4.Topological;
|
||||||
|
|
||||||
|
public class WordNet {
|
||||||
|
|
||||||
|
private RedBlackBST<String, Bag<Integer>> nouns_BST;
|
||||||
|
|
||||||
|
private String[] sysnet_array;
|
||||||
|
private Digraph word_graph;
|
||||||
|
private int n_synset;
|
||||||
|
private SAP sapFinder;
|
||||||
|
|
||||||
|
// constructor takes the name of the two input files
|
||||||
|
public WordNet(String synsets, String hypernyms){
|
||||||
|
if (synsets == null || hypernyms == null){
|
||||||
|
throw new IllegalArgumentException("Null argument(s) detected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a noun self balancing BST for gurantee log n serach
|
||||||
|
// Key of BST is the string, while the value is the Bag of synset id which the string belongs to
|
||||||
|
|
||||||
|
// Get all the lines
|
||||||
|
In in = new In(synsets);
|
||||||
|
String[] lines = in.readAllLines();
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
n_synset = lines.length;
|
||||||
|
nouns_BST = new RedBlackBST<String, Bag<Integer>>();
|
||||||
|
sysnet_array = new String[n_synset];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for(String line:lines) {
|
||||||
|
String[] parts = line.split(",");
|
||||||
|
|
||||||
|
sysnet_array[i] = parts[1];
|
||||||
|
|
||||||
|
// Split the synset to get the noun, put the noun and id in BST
|
||||||
|
String[] nouns = parts[1].split(" ");
|
||||||
|
for(String noun : nouns){
|
||||||
|
if (nouns_BST.contains(noun)){
|
||||||
|
// If noun is already in BST
|
||||||
|
// Get its id Bag and add the current id
|
||||||
|
// This is fine since Bag is mutable
|
||||||
|
nouns_BST.get(noun).add(i);
|
||||||
|
}else{
|
||||||
|
Bag<Integer> bag = new Bag<Integer>();
|
||||||
|
bag.add(i);
|
||||||
|
nouns_BST.put(noun, bag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the Digraph from the hypernyms
|
||||||
|
word_graph = new Digraph(n_synset);
|
||||||
|
in = new In(hypernyms);
|
||||||
|
while (!in.isEmpty()) {
|
||||||
|
String line = in.readLine();
|
||||||
|
String[] parts = line.split(",");
|
||||||
|
int from = Integer.parseInt(parts[0]);
|
||||||
|
|
||||||
|
for(int j=1;j<parts.length;j++){
|
||||||
|
word_graph.addEdge(from, Integer.parseInt(parts[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
// Check for DAG
|
||||||
|
Topological topological = new Topological(word_graph);
|
||||||
|
if (!topological.hasOrder())
|
||||||
|
throw new IllegalArgumentException("The graph is not DAG");
|
||||||
|
|
||||||
|
// Final check: the root
|
||||||
|
// A rooted DAG would have only one node with no outdegree
|
||||||
|
int n_root=0;
|
||||||
|
for (int v : topological.order()){
|
||||||
|
if (word_graph.outdegree(v)==0){
|
||||||
|
n_root++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n_root != 1){
|
||||||
|
throw new IllegalArgumentException("The DAG is not rooted");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a SAP for finding SAP later
|
||||||
|
sapFinder = new SAP(word_graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns all WordNet nouns
|
||||||
|
public Iterable<String> nouns(){
|
||||||
|
return nouns_BST.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
// is the word a WordNet noun?
|
||||||
|
public boolean isNoun(String word){
|
||||||
|
if (word == null){
|
||||||
|
throw new IllegalArgumentException("Word is null");
|
||||||
|
}
|
||||||
|
return nouns_BST.contains(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
// distance between nounA and nounB (defined below)
|
||||||
|
public int distance(String nounA, String nounB){
|
||||||
|
if (nounA == null || nounB == null){
|
||||||
|
throw new IllegalArgumentException("Null input(s) detected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNoun(nounA) || !isNoun(nounB) )
|
||||||
|
throw new IllegalArgumentException("Input is not in WordNet");
|
||||||
|
|
||||||
|
// This is fine
|
||||||
|
if (nounA.equals(nounB)){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because it is a rooted DAG, one common ancestor is always the root
|
||||||
|
return sapFinder.length(nouns_BST.get(nounA), nouns_BST.get(nounB));
|
||||||
|
}
|
||||||
|
|
||||||
|
// a synset (second field of synsets.txt) that is the common ancestor of nounA and nounB
|
||||||
|
// in a shortest ancestral path (defined below)
|
||||||
|
public String sap(String nounA, String nounB){
|
||||||
|
if (nounA == null || nounB == null){
|
||||||
|
throw new IllegalArgumentException("Null input(s) detected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNoun(nounA) || !isNoun(nounB) )
|
||||||
|
throw new IllegalArgumentException("Input is not in WordNet");
|
||||||
|
|
||||||
|
return sysnet_array[sapFinder.ancestor(nouns_BST.get(nounA), nouns_BST.get(nounB))];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
WordNet word_net = new WordNet("synsets.txt", "hypernyms.txt");
|
||||||
|
/*Iterable<String> nouns = word_net.nouns();
|
||||||
|
for (String word : nouns){
|
||||||
|
System.out.println(word);
|
||||||
|
}*/
|
||||||
|
System.out.println(word_net.isNoun("ASCII"));
|
||||||
|
System.out.println(word_net.isNoun("orange_juice"));
|
||||||
|
System.out.println(word_net.isNoun("thrush"));
|
||||||
|
System.out.println(word_net.distance("do-si-do", "contredanse"));
|
||||||
|
System.out.println(word_net.sap("do-si-do", "contredanse"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,381 @@
|
||||||
|
import edu.princeton.cs.algs4.Picture;
|
||||||
|
import edu.princeton.cs.algs4.Stack;
|
||||||
|
|
||||||
|
public class SeamCarver {
|
||||||
|
private Picture current_pic;
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private final int R_BITMASK = 0xFF0000;
|
||||||
|
private final int G_BITMASK = 0x00FF00;
|
||||||
|
private final int B_BITMASK = 0x0000FF;
|
||||||
|
|
||||||
|
private double[][] energies;
|
||||||
|
|
||||||
|
private class HorizontalSeamSearcher{
|
||||||
|
// Expects Picture Graph is DAG
|
||||||
|
// Use Acyclic SP procedures
|
||||||
|
public double[] distTo; // distTo[v] = distance of shortest s->v path
|
||||||
|
public int[] edgeTo; // edgeTo[v] = last edge on shortest s->v path
|
||||||
|
|
||||||
|
public HorizontalSeamSearcher() {
|
||||||
|
int V = width * height + 2;
|
||||||
|
distTo = new double[V];
|
||||||
|
edgeTo = new int[V];
|
||||||
|
|
||||||
|
for (int v = 0; v < V; v++)
|
||||||
|
distTo[v] = Double.POSITIVE_INFINITY;
|
||||||
|
distTo[0] = 0.0;
|
||||||
|
|
||||||
|
for (int i=0;i<height;i++)
|
||||||
|
relax(0, 1+i*width);
|
||||||
|
|
||||||
|
for (int col=0; col<width; col++) {
|
||||||
|
for (int row=0; row<height; row++) {
|
||||||
|
int v = row*width + col+1;
|
||||||
|
if (col< width -1){
|
||||||
|
relax(v, v+1);
|
||||||
|
if (row > 0){
|
||||||
|
relax(v, v+1-width);
|
||||||
|
}
|
||||||
|
if (row < height - 1){
|
||||||
|
relax(v, v+1+width);
|
||||||
|
}
|
||||||
|
}else if (col == width -1){
|
||||||
|
relax(v, V-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// relax edge e
|
||||||
|
private void relax(int v, int w) {
|
||||||
|
double weight = 0;
|
||||||
|
if (w != width* height + 1){
|
||||||
|
int row = (w-1) / width;
|
||||||
|
int col = (w-1) % width;
|
||||||
|
weight = energies[row][col];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distTo[w] > distTo[v] + weight) {
|
||||||
|
distTo[w] = distTo[v] + weight;
|
||||||
|
edgeTo[w] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Iterable<Integer> getSeam() {
|
||||||
|
int v = edgeTo.length - 1;
|
||||||
|
Stack<Integer> path = new Stack<Integer>();
|
||||||
|
for (int e = edgeTo[v]; e != 0; e = edgeTo[e]) {
|
||||||
|
path.push(e);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class VerticalSeamSearcher{
|
||||||
|
// Expects Picture Graph is DAG
|
||||||
|
// Use Acyclic SP procedures
|
||||||
|
public double[] distTo; // distTo[v] = distance of shortest s->v path
|
||||||
|
public int[] edgeTo; // edgeTo[v] = last edge on shortest s->v path
|
||||||
|
|
||||||
|
public VerticalSeamSearcher() {
|
||||||
|
int V = width * height + 2;
|
||||||
|
distTo = new double[V];
|
||||||
|
edgeTo = new int[V];
|
||||||
|
|
||||||
|
for (int v = 0; v < V; v++)
|
||||||
|
distTo[v] = Double.POSITIVE_INFINITY;
|
||||||
|
distTo[0] = 0.0;
|
||||||
|
|
||||||
|
// Topological sort should always have 0 as the first index
|
||||||
|
/*int[] topological = G.topologicalSort();
|
||||||
|
// Topological sort should always have "end" as the last index
|
||||||
|
assert topological[topological.length-1] == G.V-1;
|
||||||
|
|
||||||
|
}*/
|
||||||
|
for (int v=0; v< V; v++) {
|
||||||
|
//for (PictureEdge e : G.adj(v))
|
||||||
|
int row = (v-1) / width;
|
||||||
|
if (v==0){
|
||||||
|
for (int i=1;i<=width;i++)
|
||||||
|
relax(v, i);
|
||||||
|
}
|
||||||
|
else if (row< height -1){
|
||||||
|
relax(v, v+width);
|
||||||
|
int col = (v-1) % width;
|
||||||
|
if (col > 0){
|
||||||
|
relax(v, v+width-1);
|
||||||
|
}
|
||||||
|
if (col < width - 1){
|
||||||
|
relax(v, v+width+1);
|
||||||
|
}
|
||||||
|
}else if (row == height -1){
|
||||||
|
relax(v, V-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// relax edge e
|
||||||
|
private void relax(int v, int w) {
|
||||||
|
double weight = 0;
|
||||||
|
if (w != width* height + 1){
|
||||||
|
int row = (w-1) / width;
|
||||||
|
int col = (w-1) % width;
|
||||||
|
weight = energies[row][col];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distTo[w] > distTo[v] + weight) {
|
||||||
|
distTo[w] = distTo[v] + weight;
|
||||||
|
edgeTo[w] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Iterable<Integer> getSeam() {
|
||||||
|
int v = edgeTo.length - 1;
|
||||||
|
Stack<Integer> path = new Stack<Integer>();
|
||||||
|
for (int e = edgeTo[v]; e != 0; e = edgeTo[e]) {
|
||||||
|
path.push(e);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a seam carver object based on the given picture
|
||||||
|
public SeamCarver(Picture picture){
|
||||||
|
if (picture==null){
|
||||||
|
throw new IllegalArgumentException("Null input");
|
||||||
|
}
|
||||||
|
// Save a copy of the picture
|
||||||
|
current_pic = new Picture(picture);
|
||||||
|
// Get the dimensions
|
||||||
|
width = picture.width();
|
||||||
|
height = picture.height();
|
||||||
|
|
||||||
|
// Init energy array and border values
|
||||||
|
energies = new double[height][width];
|
||||||
|
for(int i=0;i<width;i++){
|
||||||
|
energies[0][i] = 1000;
|
||||||
|
energies[height-1][i] = 1000;
|
||||||
|
}
|
||||||
|
for(int i=1;i<height-1;i++){
|
||||||
|
energies[i][0] = 1000;
|
||||||
|
energies[i][width-1] = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calcualte the energy and store in the array
|
||||||
|
for(int i=1;i<width-1;i++){
|
||||||
|
for(int j=1;j<height-1;j++){
|
||||||
|
recompute_energy(j, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Construct the graph
|
||||||
|
//construct_graph();
|
||||||
|
}
|
||||||
|
|
||||||
|
// current picture
|
||||||
|
public Picture picture(){
|
||||||
|
return new Picture(current_pic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// width of current picture
|
||||||
|
public int width(){
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// height of current picture
|
||||||
|
public int height(){
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// energy of pixel at column x and row y
|
||||||
|
public double energy(int x, int y){
|
||||||
|
if (x<0 || x>=width || y <0 || y>=height){
|
||||||
|
throw new IllegalArgumentException("Input out of range");
|
||||||
|
}
|
||||||
|
return energies[y][x];
|
||||||
|
}
|
||||||
|
|
||||||
|
// sequence of indices for horizontal seam
|
||||||
|
public int[] findHorizontalSeam(){
|
||||||
|
// Run SeamSearcher on the horizontal graph
|
||||||
|
HorizontalSeamSearcher seam = new HorizontalSeamSearcher();
|
||||||
|
|
||||||
|
int[] path = new int[width];
|
||||||
|
int i=0;
|
||||||
|
for (Integer node : seam.getSeam()){
|
||||||
|
path[i++] = (node-1) / width ;
|
||||||
|
if (i==width)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sequence of indices for vertical seam
|
||||||
|
public int[] findVerticalSeam(){
|
||||||
|
// Run SeamSearcher on the vertical graph
|
||||||
|
VerticalSeamSearcher seam = new VerticalSeamSearcher();
|
||||||
|
int[] path = new int[height];
|
||||||
|
int i=0;
|
||||||
|
for (int node : seam.getSeam()){
|
||||||
|
path[i++] = (node-1) % width;
|
||||||
|
if (i==height)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check_seam(int[] seam){
|
||||||
|
int prev_ind = seam[0];
|
||||||
|
for(int i=1;i<seam.length;i++){
|
||||||
|
if (Math.abs(seam[i]-prev_ind) > 1)
|
||||||
|
throw new IllegalArgumentException("Seam has a non adjacent index");
|
||||||
|
prev_ind = seam[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove horizontal seam from current picture
|
||||||
|
public void removeHorizontalSeam(int[] seam){
|
||||||
|
if (seam==null){
|
||||||
|
throw new IllegalArgumentException("Null input");
|
||||||
|
}
|
||||||
|
if (seam.length != width){
|
||||||
|
throw new IllegalArgumentException("seam not equal to width");
|
||||||
|
}
|
||||||
|
if (height <= 1){
|
||||||
|
throw new IllegalArgumentException("Cannot carve pic any further");
|
||||||
|
}
|
||||||
|
check_seam(seam);
|
||||||
|
|
||||||
|
// Create a new Picture with the current dimensions
|
||||||
|
Picture newPicture = new Picture(width, height-1);
|
||||||
|
// Fill in the Picture except the carved pixels
|
||||||
|
// Resize the energies
|
||||||
|
for(int col=0;col<width;col++){
|
||||||
|
int r=0;
|
||||||
|
for (int row=0;row<height;row++){
|
||||||
|
if (row != seam[col]){
|
||||||
|
newPicture.set(col,r, current_pic.get(col, row));
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_pic = newPicture;
|
||||||
|
|
||||||
|
height--;
|
||||||
|
for (int col=1;col<width-1;col++){
|
||||||
|
int r = seam[col];
|
||||||
|
boolean shifting = (r==seam[col-1] && r==seam[col+1]);
|
||||||
|
for (int row = r-1; row<height;row++){
|
||||||
|
if(row<=0){
|
||||||
|
continue;
|
||||||
|
}else if (row == height-1){
|
||||||
|
energies[row][col] = 1000;
|
||||||
|
}
|
||||||
|
else if(row== r-1 || row == r || row == r+1){
|
||||||
|
recompute_energy(row, col);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(shifting){
|
||||||
|
energies[row][col] = energies[row+1][col];
|
||||||
|
}else{
|
||||||
|
recompute_energy(row, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove vertical seam from current picture
|
||||||
|
public void removeVerticalSeam(int[] seam){
|
||||||
|
if (seam==null){
|
||||||
|
throw new IllegalArgumentException("Null input");
|
||||||
|
}
|
||||||
|
if (seam.length != height){
|
||||||
|
throw new IllegalArgumentException("seam not equal to height");
|
||||||
|
}
|
||||||
|
if (width <= 1){
|
||||||
|
throw new IllegalArgumentException("Cannot carve pic any further");
|
||||||
|
}
|
||||||
|
check_seam(seam);
|
||||||
|
|
||||||
|
// Create a new Picture with the current dimensions
|
||||||
|
Picture newPicture = new Picture(width-1, height);
|
||||||
|
// Fill in the Picture except the carved pixels
|
||||||
|
// Resize the energies
|
||||||
|
for (int row=0;row<height;row++){
|
||||||
|
int c=0;
|
||||||
|
for(int col=0;col<width;col++){
|
||||||
|
if (col != seam[row]){
|
||||||
|
newPicture.set(c,row, current_pic.get(col, row));
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_pic = newPicture;
|
||||||
|
width--;
|
||||||
|
|
||||||
|
for (int row=1;row<height-1;row++){
|
||||||
|
// Recompute for i-1 and i
|
||||||
|
int c = seam[row];
|
||||||
|
boolean shifting = (c==seam[row-1] && c==seam[row+1]);
|
||||||
|
|
||||||
|
for (int col = c-1; col<width;col++){
|
||||||
|
if(col<=0){
|
||||||
|
continue;
|
||||||
|
}else if (col == width-1){
|
||||||
|
energies[row][col] = 1000;
|
||||||
|
}
|
||||||
|
else if(col== c-1 || col == c || col == c+1){
|
||||||
|
recompute_energy(row, col);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(shifting){
|
||||||
|
energies[row][col] = energies[row][col+1];
|
||||||
|
}else{
|
||||||
|
recompute_energy(row, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recompute_energy(int row, int col){
|
||||||
|
int prevx_RGB = current_pic.getRGB(col-1, row);
|
||||||
|
int nextx_RGB = current_pic.getRGB(col+1, row);
|
||||||
|
double Rx = ((prevx_RGB & R_BITMASK)>>16) - ((nextx_RGB & R_BITMASK)>>16);
|
||||||
|
double Gx = ((prevx_RGB & G_BITMASK)>>8) - ((nextx_RGB & G_BITMASK)>>8);
|
||||||
|
double Bx = (prevx_RGB & B_BITMASK) - (nextx_RGB & B_BITMASK);
|
||||||
|
double deltax2 = Math.pow(Rx, 2) + Math.pow(Gx, 2) + Math.pow(Bx, 2);
|
||||||
|
|
||||||
|
|
||||||
|
int prevy_RGB = current_pic.getRGB(col, row-1);
|
||||||
|
int nexty_RGB = current_pic.getRGB(col, row+1);
|
||||||
|
double Ry = ((prevy_RGB & R_BITMASK)>>16) - ((nexty_RGB & R_BITMASK)>>16);
|
||||||
|
double Gy = ((prevy_RGB & G_BITMASK)>>8) - ((nexty_RGB & G_BITMASK)>>8);
|
||||||
|
double By = (prevy_RGB & B_BITMASK) - (nexty_RGB & B_BITMASK);
|
||||||
|
double deltay2 = Math.pow(Ry, 2) + Math.pow(Gy, 2) + Math.pow(By, 2);
|
||||||
|
energies[row][col] = Math.sqrt(deltax2 + deltay2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// unit testing (optional)
|
||||||
|
public static void main(String[] args){
|
||||||
|
Picture pic = new Picture("cherrim.png");
|
||||||
|
|
||||||
|
SeamCarver carver = new SeamCarver(pic);
|
||||||
|
System.out.println(carver.width());
|
||||||
|
System.out.println(carver.height());
|
||||||
|
int n_vcuts = carver.width()/4;
|
||||||
|
int n_hcuts = carver.height()/4;
|
||||||
|
int[] seam;
|
||||||
|
for (int i=0;i<n_vcuts;i++){
|
||||||
|
seam = carver.findVerticalSeam();
|
||||||
|
carver.removeVerticalSeam(seam);
|
||||||
|
}
|
||||||
|
for (int i=0;i<n_hcuts;i++){
|
||||||
|
seam = carver.findHorizontalSeam();
|
||||||
|
carver.removeHorizontalSeam(seam);
|
||||||
|
}
|
||||||
|
carver.picture().save("trimmed_cherrim.png");
|
||||||
|
//carver.picture().show();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,307 @@
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import edu.princeton.cs.algs4.In;
|
||||||
|
import edu.princeton.cs.algs4.BST;
|
||||||
|
import edu.princeton.cs.algs4.FlowEdge;
|
||||||
|
import edu.princeton.cs.algs4.FlowNetwork;
|
||||||
|
import edu.princeton.cs.algs4.FordFulkerson;
|
||||||
|
|
||||||
|
|
||||||
|
public class BaseballElimination{
|
||||||
|
private final int n_teams;
|
||||||
|
private final BST<String, Integer> teamNames;
|
||||||
|
private final String[] teamNamesind;
|
||||||
|
private final int[][] teamStats;
|
||||||
|
private final int[][] matches;
|
||||||
|
// create a baseball division from given filename in format specified below
|
||||||
|
public BaseballElimination(String filename){
|
||||||
|
In in = new In(filename);
|
||||||
|
n_teams = in.readInt();
|
||||||
|
|
||||||
|
teamNames = new BST<String, Integer>();
|
||||||
|
teamNamesind = new String[n_teams];
|
||||||
|
teamStats = new int[n_teams][3];
|
||||||
|
matches = new int[n_teams][n_teams];
|
||||||
|
|
||||||
|
for(int i=0;i<n_teams;i++){
|
||||||
|
String name = in.readString();
|
||||||
|
teamNames.put(name, i);
|
||||||
|
teamNamesind[i] = name;
|
||||||
|
for (int j=0;j<3;j++){
|
||||||
|
teamStats[i][j] = in.readInt();
|
||||||
|
}
|
||||||
|
for (int j=0;j<n_teams;j++){
|
||||||
|
matches[i][j] = in.readInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
// number of teams
|
||||||
|
public int numberOfTeams(){
|
||||||
|
return n_teams;
|
||||||
|
}
|
||||||
|
// all teams
|
||||||
|
public Iterable<String> teams(){
|
||||||
|
return teamNames.keys();
|
||||||
|
}
|
||||||
|
// number of wins for given team
|
||||||
|
public int wins(String team){
|
||||||
|
Integer n = teamNames.get(team);
|
||||||
|
if(n == null){
|
||||||
|
throw new IllegalArgumentException("Team not found");
|
||||||
|
}
|
||||||
|
return teamStats[n][0];
|
||||||
|
}
|
||||||
|
// number of losses for given team
|
||||||
|
public int losses(String team) {
|
||||||
|
Integer n = teamNames.get(team);
|
||||||
|
if(n == null){
|
||||||
|
throw new IllegalArgumentException("Team not found");
|
||||||
|
}
|
||||||
|
return teamStats[n][1];
|
||||||
|
}
|
||||||
|
// number of remaining games for given team
|
||||||
|
public int remaining(String team){
|
||||||
|
Integer n = teamNames.get(team);
|
||||||
|
if(n == null){
|
||||||
|
throw new IllegalArgumentException("Team not found");
|
||||||
|
}
|
||||||
|
return teamStats[n][2];
|
||||||
|
}
|
||||||
|
// number of remaining games between team1 and team2
|
||||||
|
public int against(String team1, String team2) {
|
||||||
|
Integer m = teamNames.get(team1);
|
||||||
|
Integer n = teamNames.get(team2);
|
||||||
|
if(m == null){
|
||||||
|
throw new IllegalArgumentException("Team 1 not found");
|
||||||
|
}
|
||||||
|
if(n == null){
|
||||||
|
throw new IllegalArgumentException("Team 2 not found");
|
||||||
|
}
|
||||||
|
return matches[m][n];
|
||||||
|
}
|
||||||
|
// is given team eliminated?
|
||||||
|
public boolean isEliminated(String team) {
|
||||||
|
Integer ind = teamNames.get(team);
|
||||||
|
if(ind == null){
|
||||||
|
throw new IllegalArgumentException("Team not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
int possible_wins = teamStats[ind][0] + teamStats[ind][2];
|
||||||
|
//Trivial check
|
||||||
|
for(int i=0;i<n_teams;i++){
|
||||||
|
if(i==ind)
|
||||||
|
continue;
|
||||||
|
if(possible_wins<teamStats[i][0]){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowEdge e;
|
||||||
|
int n_nodes = n_teams + 1 + (n_teams - 1) * (n_teams -2) / 2;
|
||||||
|
FlowNetwork elim_network = new FlowNetwork(n_nodes);
|
||||||
|
|
||||||
|
// Init 0 to n_teams-2 as team node
|
||||||
|
// Init 0.5 * n_teams(n_teams-1) as the reamining matches
|
||||||
|
// Connect each match to the respective teams
|
||||||
|
int n=0;
|
||||||
|
for(int i=0;i<n_teams-1;i++){
|
||||||
|
for(int j=i+1;j<n_teams-1;j++){
|
||||||
|
e = new FlowEdge(n_teams-1+n, i, Double.POSITIVE_INFINITY);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
e = new FlowEdge(n_teams-1+n, j, Double.POSITIVE_INFINITY);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init two more nodes as s and t
|
||||||
|
// s is second-to-last, t is the last
|
||||||
|
// Connect s to each match with their respective number
|
||||||
|
n=0;
|
||||||
|
for (int j=0;j<n_teams;j++){
|
||||||
|
if(j==ind)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
e = new FlowEdge(n, n_nodes-1, possible_wins-teamStats[j][0]);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect t to each team with the remaining games to win
|
||||||
|
int other_games = 0;
|
||||||
|
n=0;
|
||||||
|
for (int j=0;j<n_teams-1;j++){ // Last row is not needed
|
||||||
|
if(j==ind)
|
||||||
|
continue;
|
||||||
|
for (int k=j+1;k<n_teams;k++){
|
||||||
|
if(k==ind)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
other_games += matches[j][k];
|
||||||
|
e = new FlowEdge(n_nodes-2, n_teams-1+n, matches[j][k]);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.out.println(elim_network.toString());
|
||||||
|
FordFulkerson flow = new FordFulkerson(elim_network, n_nodes-2, n_nodes-1);
|
||||||
|
if (flow.value() < other_games){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// subset R of teams that eliminates given team; null if not eliminated
|
||||||
|
public Iterable<String> certificateOfElimination(String team) {
|
||||||
|
Integer ind = teamNames.get(team);
|
||||||
|
if(ind == null){
|
||||||
|
throw new IllegalArgumentException("Team not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int possible_wins = teamStats[ind][0] + teamStats[ind][2];
|
||||||
|
//Trivial check
|
||||||
|
String[] team_set = new String[n_teams];
|
||||||
|
int n=0,v=0;
|
||||||
|
for(int i=0;i<n_teams;i++){
|
||||||
|
if(i==ind)
|
||||||
|
continue;
|
||||||
|
if(possible_wins<teamStats[i][0]){
|
||||||
|
team_set[n++] = teamNamesind[i];
|
||||||
|
}
|
||||||
|
v++;
|
||||||
|
}
|
||||||
|
if (n>0)
|
||||||
|
return new teamIterable(team_set, n);
|
||||||
|
|
||||||
|
FlowEdge e;
|
||||||
|
int n_nodes = n_teams + 1 + (n_teams - 1) * (n_teams -2) / 2;
|
||||||
|
FlowNetwork elim_network = new FlowNetwork(n_nodes);
|
||||||
|
|
||||||
|
// Init 0 to n_teams-2 as team node
|
||||||
|
// Init 0.5 * n_teams(n_teams-1) as the reamining matches
|
||||||
|
// Connect each match to the respective teams
|
||||||
|
n=0;
|
||||||
|
for(int i=0;i<n_teams-1;i++){
|
||||||
|
for(int j=i+1;j<n_teams-1;j++){
|
||||||
|
e = new FlowEdge(n_teams-1+n, i, Double.POSITIVE_INFINITY);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
e = new FlowEdge(n_teams-1+n, j, Double.POSITIVE_INFINITY);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init two more nodes as s and t
|
||||||
|
// s is second-to-last, t is the last
|
||||||
|
// Connect s to each match with their respective number
|
||||||
|
n=0;
|
||||||
|
for (int j=0;j<n_teams;j++){
|
||||||
|
if(j==ind)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
e = new FlowEdge(n, n_nodes-1, possible_wins-teamStats[j][0]);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect t to each team with the remaining games to win
|
||||||
|
int other_games = 0;
|
||||||
|
n=0;
|
||||||
|
for (int j=0;j<n_teams-1;j++){
|
||||||
|
if(j==ind)
|
||||||
|
continue;
|
||||||
|
for (int k=j+1;k<n_teams;k++){
|
||||||
|
if(k==ind)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
other_games += matches[j][k];
|
||||||
|
e = new FlowEdge(n_nodes-2, n_teams-1+n, matches[j][k]);
|
||||||
|
elim_network.addEdge(e);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//System.out.println(elim_network.toString());
|
||||||
|
FordFulkerson flow = new FordFulkerson(elim_network, n_nodes-2, n_nodes-1);
|
||||||
|
if (flow.value() < other_games){
|
||||||
|
n=0;v=0;
|
||||||
|
for (int i=0;i<n_teams;i++){
|
||||||
|
if(i==ind)
|
||||||
|
continue;
|
||||||
|
if (flow.inCut(v)){
|
||||||
|
team_set[n++] = teamNamesind[i];
|
||||||
|
}
|
||||||
|
v++;
|
||||||
|
}
|
||||||
|
return new teamIterable(team_set, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class teamIterable implements Iterable<String>{
|
||||||
|
String[] names;
|
||||||
|
|
||||||
|
public teamIterable(String[] names, int length){
|
||||||
|
this.names = new String[length];
|
||||||
|
for(int i=0;i<length;i++){
|
||||||
|
this.names[i] = names[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<String> iterator(){
|
||||||
|
return new teamIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class teamIterator implements Iterator<String>{
|
||||||
|
int current = 0;
|
||||||
|
|
||||||
|
public boolean hasNext(){
|
||||||
|
return current < names.length;
|
||||||
|
}
|
||||||
|
public String next(){
|
||||||
|
return names[current++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
BaseballElimination bball = new BaseballElimination("teams4a.txt");
|
||||||
|
|
||||||
|
int N = bball.numberOfTeams();
|
||||||
|
System.out.println(N);
|
||||||
|
for(String s: bball.teams()){
|
||||||
|
System.out.print(s);
|
||||||
|
System.out.print(" ");
|
||||||
|
System.out.print(bball.wins(s));
|
||||||
|
System.out.print(" ");
|
||||||
|
System.out.print(bball.losses(s));
|
||||||
|
System.out.print(" ");
|
||||||
|
System.out.print(bball.remaining(s));
|
||||||
|
System.out.print(" ");
|
||||||
|
for(String t: bball.teams()){
|
||||||
|
System.out.print(bball.against(s, t));
|
||||||
|
System.out.print(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterable<String> elim = bball.certificateOfElimination(s);
|
||||||
|
//System.out.print(elim);
|
||||||
|
if (elim != null){
|
||||||
|
System.out.print(" Eliminated by: ");
|
||||||
|
for(String t: bball.certificateOfElimination(s)){
|
||||||
|
System.out.print(t);
|
||||||
|
System.out.print(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,231 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Compilation: javac BoggleBoard.java
|
||||||
|
* Execution: java BoggleBoard
|
||||||
|
* Dependencies: StdRandom.java In.java StdOut.java
|
||||||
|
*
|
||||||
|
* A data type for Boggle boards.
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
import edu.princeton.cs.algs4.In;
|
||||||
|
import edu.princeton.cs.algs4.StdOut;
|
||||||
|
import edu.princeton.cs.algs4.StdRandom;
|
||||||
|
|
||||||
|
public class BoggleBoard {
|
||||||
|
// the 16 Boggle dice (1992 version)
|
||||||
|
private static final String[] BOGGLE_1992 = {
|
||||||
|
"LRYTTE", "VTHRWE", "EGHWNE", "SEOTIS",
|
||||||
|
"ANAEEG", "IDSYTT", "OATTOW", "MTOICU",
|
||||||
|
"AFPKFS", "XLDERI", "HCPOAS", "ENSIEU",
|
||||||
|
"YLDEVR", "ZNRNHL", "NMIQHU", "OBBAOJ"
|
||||||
|
};
|
||||||
|
|
||||||
|
// the 16 Boggle dice (1983 version)
|
||||||
|
private static final String[] BOGGLE_1983 = {
|
||||||
|
"AACIOT", "ABILTY", "ABJMOQ", "ACDEMP",
|
||||||
|
"ACELRS", "ADENVZ", "AHMORS", "BIFORX",
|
||||||
|
"DENOSW", "DKNOTU", "EEFHIY", "EGINTV",
|
||||||
|
"EGKLUY", "EHINPS", "ELPSTU", "GILRUW",
|
||||||
|
};
|
||||||
|
|
||||||
|
// the 25 Boggle Master / Boggle Deluxe dice
|
||||||
|
private static final String[] BOGGLE_MASTER = {
|
||||||
|
"AAAFRS", "AAEEEE", "AAFIRS", "ADENNN", "AEEEEM",
|
||||||
|
"AEEGMU", "AEGMNN", "AFIRSY", "BJKQXZ", "CCNSTW",
|
||||||
|
"CEIILT", "CEILPT", "CEIPST", "DDLNOR", "DHHLOR",
|
||||||
|
"DHHNOT", "DHLNOR", "EIIITT", "EMOTTT", "ENSSSU",
|
||||||
|
"FIPRSY", "GORRVW", "HIPRRY", "NOOTUW", "OOOTTU"
|
||||||
|
};
|
||||||
|
|
||||||
|
// the 25 Big Boggle dice
|
||||||
|
private static final String[] BOGGLE_BIG = {
|
||||||
|
"AAAFRS", "AAEEEE", "AAFIRS", "ADENNN", "AEEEEM",
|
||||||
|
"AEEGMU", "AEGMNN", "AFIRSY", "BJKQXZ", "CCENST",
|
||||||
|
"CEIILT", "CEILPT", "CEIPST", "DDHNOT", "DHHLOR",
|
||||||
|
"DHLNOR", "DHLNOR", "EIIITT", "EMOTTT", "ENSSSU",
|
||||||
|
"FIPRSY", "GORRVW", "IPRRRY", "NOOTUW", "OOOTTU"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// letters and frequencies of letters in the English alphabet
|
||||||
|
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
private static final double[] FREQUENCIES = {
|
||||||
|
0.08167, 0.01492, 0.02782, 0.04253, 0.12703, 0.02228,
|
||||||
|
0.02015, 0.06094, 0.06966, 0.00153, 0.00772, 0.04025,
|
||||||
|
0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987,
|
||||||
|
0.06327, 0.09056, 0.02758, 0.00978, 0.02360, 0.00150,
|
||||||
|
0.01974, 0.00074
|
||||||
|
};
|
||||||
|
|
||||||
|
private final int m; // number of rows
|
||||||
|
private final int n; // number of columns
|
||||||
|
private char[][] board; // the m-by-n array of characters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a random 4-by-4 board, by rolling the Hasbro dice.
|
||||||
|
*/
|
||||||
|
public BoggleBoard() {
|
||||||
|
m = 4;
|
||||||
|
n = 4;
|
||||||
|
StdRandom.shuffle(BOGGLE_1992);
|
||||||
|
board = new char[m][n];
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
String letters = BOGGLE_1992[n*i+j];
|
||||||
|
int r = StdRandom.uniform(letters.length());
|
||||||
|
board[i][j] = letters.charAt(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a board from the given filename.
|
||||||
|
* @param filename the name of the file containing the Boggle board
|
||||||
|
*/
|
||||||
|
public BoggleBoard(String filename) {
|
||||||
|
In in = new In(filename);
|
||||||
|
m = in.readInt();
|
||||||
|
n = in.readInt();
|
||||||
|
if (m <= 0) throw new IllegalArgumentException("number of rows must be a positive integer");
|
||||||
|
if (n <= 0) throw new IllegalArgumentException("number of columns must be a positive integer");
|
||||||
|
board = new char[m][n];
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
String letter = in.readString().toUpperCase();
|
||||||
|
if (letter.equals("QU"))
|
||||||
|
board[i][j] = 'Q';
|
||||||
|
else if (letter.length() != 1)
|
||||||
|
throw new IllegalArgumentException("invalid character: " + letter);
|
||||||
|
else if (!ALPHABET.contains(letter))
|
||||||
|
throw new IllegalArgumentException("invalid character: " + letter);
|
||||||
|
else
|
||||||
|
board[i][j] = letter.charAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a random m-by-n board, according to the frequency
|
||||||
|
* of letters in the English language.
|
||||||
|
* @param m the number of rows
|
||||||
|
* @param n the number of columns
|
||||||
|
*/
|
||||||
|
public BoggleBoard(int m, int n) {
|
||||||
|
this.m = m;
|
||||||
|
this.n = n;
|
||||||
|
if (m <= 0) throw new IllegalArgumentException("number of rows must be a positive integer");
|
||||||
|
if (n <= 0) throw new IllegalArgumentException("number of columns must be a positive integer");
|
||||||
|
board = new char[m][n];
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
int r = StdRandom.discrete(FREQUENCIES);
|
||||||
|
board[i][j] = ALPHABET.charAt(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a board from the given 2d character array,
|
||||||
|
* with 'Q' representing the two-letter sequence "Qu".
|
||||||
|
* @param a the 2d character array
|
||||||
|
*/
|
||||||
|
public BoggleBoard(char[][] a) {
|
||||||
|
this.m = a.length;
|
||||||
|
if (m == 0) throw new IllegalArgumentException("number of rows must be a positive integer");
|
||||||
|
this.n = a[0].length;
|
||||||
|
if (n == 0) throw new IllegalArgumentException("number of columns must be a positive integer");
|
||||||
|
board = new char[m][n];
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
if (a[i].length != n)
|
||||||
|
throw new IllegalArgumentException("char[][] array is ragged");
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
if (ALPHABET.indexOf(a[i][j]) == -1)
|
||||||
|
throw new IllegalArgumentException("invalid character: " + a[i][j]);
|
||||||
|
board[i][j] = a[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of rows.
|
||||||
|
* @return number of rows
|
||||||
|
*/
|
||||||
|
public int rows() {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of columns.
|
||||||
|
* @return number of columns
|
||||||
|
*/
|
||||||
|
public int cols() {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the letter in row i and column j,
|
||||||
|
* with 'Q' representing the two-letter sequence "Qu".
|
||||||
|
* @param i the row
|
||||||
|
* @param j the column
|
||||||
|
* @return the letter in row i and column j
|
||||||
|
* with 'Q' representing the two-letter sequence "Qu".
|
||||||
|
*/
|
||||||
|
public char getLetter(int i, int j) {
|
||||||
|
return board[i][j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the board, replacing 'Q' with "Qu".
|
||||||
|
* @return a string representation of the board, replacing 'Q' with "Qu"
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder(m + " " + n + "\n");
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
sb.append(board[i][j]);
|
||||||
|
if (board[i][j] == 'Q') sb.append("u ");
|
||||||
|
else sb.append(" ");
|
||||||
|
}
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
return sb.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests the BoggleBoard data type.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// initialize a 4-by-4 board using Hasbro dice
|
||||||
|
StdOut.println("Hasbro board:");
|
||||||
|
BoggleBoard board1 = new BoggleBoard();
|
||||||
|
StdOut.println(board1);
|
||||||
|
StdOut.println();
|
||||||
|
|
||||||
|
// initialize a 4-by-4 board using letter frequencies in English language
|
||||||
|
StdOut.println("Random 4-by-4 board:");
|
||||||
|
BoggleBoard board2 = new BoggleBoard(4, 4);
|
||||||
|
StdOut.println(board2);
|
||||||
|
StdOut.println();
|
||||||
|
|
||||||
|
// initialize a 4-by-4 board from a 2d char array
|
||||||
|
StdOut.println("4-by-4 board from 2D character array:");
|
||||||
|
char[][] a = {
|
||||||
|
{ 'D', 'O', 'T', 'Y' },
|
||||||
|
{ 'T', 'R', 'S', 'F' },
|
||||||
|
{ 'M', 'X', 'M', 'O' },
|
||||||
|
{ 'Z', 'A', 'B', 'W' }
|
||||||
|
};
|
||||||
|
BoggleBoard board3 = new BoggleBoard(a);
|
||||||
|
StdOut.println(board3);
|
||||||
|
StdOut.println();
|
||||||
|
|
||||||
|
// initialize a 4-by-4 board from a file
|
||||||
|
String filename = "board-quinquevalencies.txt";
|
||||||
|
StdOut.println("4-by-4 board from file " + filename + ":");
|
||||||
|
BoggleBoard board4 = new BoggleBoard(filename);
|
||||||
|
StdOut.println(board4);
|
||||||
|
StdOut.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,315 @@
|
||||||
|
import edu.princeton.cs.algs4.TST;
|
||||||
|
import edu.princeton.cs.algs4.In;
|
||||||
|
import edu.princeton.cs.algs4.StdOut;
|
||||||
|
|
||||||
|
public class BoggleSolver
|
||||||
|
{
|
||||||
|
private BoggleDict dict;
|
||||||
|
private static final int FIRST_LETTER = 65;
|
||||||
|
private static final int[] SCORE = new int[]{1,1,2,3,5,11};
|
||||||
|
|
||||||
|
// Initializes the data structure using the given array of strings as the dictionary.
|
||||||
|
// (You can assume each word in the dictionary contains only the uppercase letters A through Z.)
|
||||||
|
public BoggleSolver(String[] dictionary){
|
||||||
|
dict = new BoggleDict(dictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the set of all valid words in the given Boggle board, as an Iterable.
|
||||||
|
public Iterable<String> getAllValidWords(BoggleBoard board){
|
||||||
|
int rows = board.rows();
|
||||||
|
int cols = board.cols();
|
||||||
|
// Because the board is a dense graph
|
||||||
|
// Just rely on row and col counts
|
||||||
|
|
||||||
|
// Prepare an array to indicate that a letter is used
|
||||||
|
boolean[][] used = new boolean[rows][cols];
|
||||||
|
// Keep TST for found words
|
||||||
|
TST<Integer> found_words = new TST<Integer>();
|
||||||
|
|
||||||
|
// This section could be cleaner
|
||||||
|
for (int r=0;r<rows;r++){
|
||||||
|
for (int c=0;c<cols;c++){
|
||||||
|
// For each node, get letter
|
||||||
|
char letter1 = board.getLetter(r, c);
|
||||||
|
// marked off the current node
|
||||||
|
used[r][c] = true;
|
||||||
|
|
||||||
|
if (letter1 == 'Q'){
|
||||||
|
// If Q, add U, check if a tst exists for 'QU', start recursive search
|
||||||
|
char letter2 = 'U';
|
||||||
|
ManualTST tst = dict.get_TST(letter1, letter2);
|
||||||
|
if (tst != null){
|
||||||
|
StringBuilder sBuilder = new StringBuilder(2);
|
||||||
|
sBuilder.append(letter1);
|
||||||
|
sBuilder.append(letter2);
|
||||||
|
for(int i=-1;i<2;i++){
|
||||||
|
int r2 = r+i;
|
||||||
|
if(r2 == -1 || r2 == rows)
|
||||||
|
continue;
|
||||||
|
for(int j=-1;j<2;j++){
|
||||||
|
int c2 = c+j;
|
||||||
|
if(c2 == -1 || c2 == cols)
|
||||||
|
continue;
|
||||||
|
if (!used[r2][c2])
|
||||||
|
recursive_search(board, tst, tst.root, used, sBuilder, found_words, r2, c2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// Otherwise, find the neighbours letters
|
||||||
|
for(int i=-1;i<2;i++){
|
||||||
|
int r2 = r+i;
|
||||||
|
if(r2 == -1 || r2 == rows)
|
||||||
|
continue;
|
||||||
|
for(int j=-1;j<2;j++){
|
||||||
|
int c2 = c+j;
|
||||||
|
if(c2 == -1 || c2 == cols)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Using the two starting letters, check if a tst exists from the R2 table
|
||||||
|
if (!used[r2][c2]){
|
||||||
|
char letter2 = board.getLetter(r2, c2);
|
||||||
|
ManualTST tst = dict.get_TST(letter1, letter2);
|
||||||
|
|
||||||
|
if (tst != null){
|
||||||
|
// If so, marked off the second node
|
||||||
|
used[r2][c2] = true;
|
||||||
|
StringBuilder sBuilder = new StringBuilder(2);
|
||||||
|
sBuilder.append(letter1);
|
||||||
|
sBuilder.append(letter2);
|
||||||
|
TSTNode start = tst.root;
|
||||||
|
|
||||||
|
//If the second letter is Q, add U, find U and step into it
|
||||||
|
if (letter2 == 'Q'){
|
||||||
|
sBuilder.append('U');
|
||||||
|
start = tst.get_next(start,'U');
|
||||||
|
start = tst.step_into(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// begin recursive search
|
||||||
|
for(int m=-1;m<2;m++){
|
||||||
|
int next_r = r2+m;
|
||||||
|
if(next_r == -1 || next_r == rows)
|
||||||
|
continue;
|
||||||
|
for(int n=-1;n<2;n++){
|
||||||
|
int next_c = c2+n;
|
||||||
|
if(next_c == -1 || next_c == cols)
|
||||||
|
continue;
|
||||||
|
if (!used[next_r][next_c]){
|
||||||
|
recursive_search(board, tst, start, used, sBuilder, found_words, next_r, next_c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unmarked the adjacent node
|
||||||
|
used[r2][c2] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unmarked the current node
|
||||||
|
used[r][c] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found_words.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recursive_search(BoggleBoard board, ManualTST tst, TSTNode tst_node, boolean[][] used, StringBuilder sBuilder, TST<Integer> found_words, int r, int c){
|
||||||
|
// perform DFS starting from the third letter
|
||||||
|
// During DFS recursion, check if the letter can be traced from the current node
|
||||||
|
char letter = board.getLetter(r, c);
|
||||||
|
TSTNode node = tst.get_next(tst_node, letter);
|
||||||
|
int n_chars = sBuilder.length() + 1;
|
||||||
|
|
||||||
|
// Find an extra U if the letter is Q
|
||||||
|
if (letter == 'Q'){
|
||||||
|
node = tst.step_into(node);
|
||||||
|
node = tst.get_next(node, 'U');
|
||||||
|
n_chars++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node != null){
|
||||||
|
// If so, mark the current char and build the string
|
||||||
|
StringBuilder next_sBuilder = new StringBuilder(n_chars);
|
||||||
|
next_sBuilder.append(sBuilder.toString());
|
||||||
|
used[r][c] = true;
|
||||||
|
next_sBuilder.append(letter);
|
||||||
|
|
||||||
|
// Add the U if the letter is Q
|
||||||
|
if (letter == 'Q')
|
||||||
|
next_sBuilder.append('U');
|
||||||
|
|
||||||
|
// Get the string if it is a valid word (i.e. score is non-zero)
|
||||||
|
// Also need to check if word already added
|
||||||
|
if (node.val >0){
|
||||||
|
found_words.put(next_sBuilder.toString(), node.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recurse the search on adjacents
|
||||||
|
for(int i=-1;i<2;i++){
|
||||||
|
int next_r = r+i;
|
||||||
|
if(next_r == -1 || next_r == board.rows())
|
||||||
|
continue;
|
||||||
|
for(int j=-1;j<2;j++){
|
||||||
|
int next_c = c+j;
|
||||||
|
if(next_c == -1 || next_c == board.cols())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!used[next_r][next_c]){
|
||||||
|
recursive_search(board, tst, tst.step_into(node), used, next_sBuilder, found_words, next_r, next_c);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When finish with a node, unmark the current letter
|
||||||
|
used[r][c] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the score of the given word if it is in the dictionary, zero otherwise.
|
||||||
|
// (You can assume the word contains only the uppercase letters A through Z.)
|
||||||
|
public int scoreOf(String word){
|
||||||
|
if(word.length()<3)
|
||||||
|
return 0;
|
||||||
|
ManualTST tst = dict.get_TST(word);
|
||||||
|
if(tst != null){
|
||||||
|
return tst.get(word.substring(2));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The dictionary is a TST+R^2 implementation
|
||||||
|
// This is used since Boggle expects 3 letters or more
|
||||||
|
// It is also expected that the chars are Uppercase
|
||||||
|
// First letter A - 65 in decimal
|
||||||
|
private class BoggleDict{
|
||||||
|
private ManualTST[][] roots; // root of TST, use an array for R2
|
||||||
|
|
||||||
|
public BoggleDict(String[] dictionary){
|
||||||
|
roots = new ManualTST[26][26];
|
||||||
|
for(String word : dictionary){
|
||||||
|
int word_len = word.length();
|
||||||
|
if (word_len>=3){
|
||||||
|
//Process here
|
||||||
|
int char1 = word.charAt(0) - FIRST_LETTER;
|
||||||
|
int char2 = word.charAt(1) - FIRST_LETTER;
|
||||||
|
String remaining = word.substring(2);
|
||||||
|
int score_ind = Math.min(word_len-2, SCORE.length)-1;
|
||||||
|
if (roots[char1][char2] == null){
|
||||||
|
roots[char1][char2] = new ManualTST();
|
||||||
|
}
|
||||||
|
roots[char1][char2].put(remaining, SCORE[score_ind]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManualTST get_TST(String word){
|
||||||
|
if (word==null) return null;
|
||||||
|
int char1 = word.charAt(0) - FIRST_LETTER;
|
||||||
|
int char2 = word.charAt(1) - FIRST_LETTER;
|
||||||
|
return roots[char1][char2];
|
||||||
|
}
|
||||||
|
public ManualTST get_TST(char c1, char c2){
|
||||||
|
int char1 = c1 - FIRST_LETTER;
|
||||||
|
int char2 = c2 - FIRST_LETTER;
|
||||||
|
return roots[char1][char2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TSTNode {
|
||||||
|
private char c; // character
|
||||||
|
private TSTNode left, mid, right; // left, middle, and right subtries
|
||||||
|
public int val; // Score for the string
|
||||||
|
}
|
||||||
|
|
||||||
|
// This TST is a striped down version of the one in algs4
|
||||||
|
// Consisting get and put
|
||||||
|
// with two extra functions for manual navigation
|
||||||
|
private class ManualTST{
|
||||||
|
public TSTNode root; // root of TST
|
||||||
|
|
||||||
|
public int get(String key) {
|
||||||
|
if (key == null) {
|
||||||
|
throw new IllegalArgumentException("calls get() with null argument");
|
||||||
|
}
|
||||||
|
if (key.length() == 0) throw new IllegalArgumentException("key must have length >= 1");
|
||||||
|
TSTNode x = get(root, key, 0);
|
||||||
|
if (x == null) return 0;
|
||||||
|
return x.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return subtrie corresponding to given key
|
||||||
|
private TSTNode get(TSTNode x, String key, int d) {
|
||||||
|
if (x == null) return null;
|
||||||
|
if (key.length() == 0) throw new IllegalArgumentException("key must have length >= 1");
|
||||||
|
char c = key.charAt(d);
|
||||||
|
if (c < x.c) return get(x.left, key, d);
|
||||||
|
else if (c > x.c) return get(x.right, key, d);
|
||||||
|
else if (d < key.length() - 1) return get(x.mid, key, d+1);
|
||||||
|
else return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(String key, int val) {
|
||||||
|
if (key == null) {
|
||||||
|
throw new IllegalArgumentException("calls put() with null key");
|
||||||
|
}
|
||||||
|
root = put(root, key, val, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TSTNode put(TSTNode x, String key, int val, int d) {
|
||||||
|
char c = key.charAt(d);
|
||||||
|
if (x == null) {
|
||||||
|
x = new TSTNode();
|
||||||
|
x.c = c;
|
||||||
|
}
|
||||||
|
if (c < x.c) x.left = put(x.left, key, val, d);
|
||||||
|
else if (c > x.c) x.right = put(x.right, key, val, d);
|
||||||
|
else if (d < key.length() - 1) x.mid = put(x.mid, key, val, d+1);
|
||||||
|
else x.val = val;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively find the node with the next char
|
||||||
|
// Stopping before entering the mid
|
||||||
|
public TSTNode get_next(TSTNode x, char next_char){
|
||||||
|
if (x == null) return null;
|
||||||
|
if (next_char < x.c) return get_next(x.left, next_char);
|
||||||
|
else if (next_char > x.c) return get_next(x.right, next_char);
|
||||||
|
else return x;
|
||||||
|
}
|
||||||
|
// Enter the mid of the node
|
||||||
|
// Should be called after get_next if it gets a node
|
||||||
|
public TSTNode step_into(TSTNode x){
|
||||||
|
if (x == null) return null;
|
||||||
|
return x.mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
In in = new In("./boards/dictionary-enable2k.txt");
|
||||||
|
String[] dictionary = in.readAllStrings();
|
||||||
|
|
||||||
|
BoggleSolver solver = new BoggleSolver(dictionary);
|
||||||
|
System.out.println("done");
|
||||||
|
String[] words = new String[]{"TIE", "SYNCHRONIZATION","HAHA", "BUY","BUSY","AO"};
|
||||||
|
for(String word : words){
|
||||||
|
System.out.println(solver.scoreOf(word));
|
||||||
|
}
|
||||||
|
|
||||||
|
int trials = 1;
|
||||||
|
|
||||||
|
BoggleBoard board ;
|
||||||
|
for(int i=0;i<trials;i++){
|
||||||
|
board = new BoggleBoard("testboard.txt");
|
||||||
|
System.out.println(board.toString());
|
||||||
|
int score = 0;
|
||||||
|
for (String word : solver.getAllValidWords(board)) {
|
||||||
|
System.out.println(word);
|
||||||
|
score += solver.scoreOf(word);
|
||||||
|
}
|
||||||
|
StdOut.println("Score = " + score);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
import edu.princeton.cs.algs4.BinaryStdIn;
|
||||||
|
import edu.princeton.cs.algs4.BinaryStdOut;
|
||||||
|
|
||||||
|
//import java.util.Arrays;
|
||||||
|
//import java.util.Comparator;
|
||||||
|
|
||||||
|
public class BurrowsWheeler{
|
||||||
|
|
||||||
|
// apply Burrows-Wheeler transform,
|
||||||
|
// reading from standard input and writing to standard output
|
||||||
|
public static void transform(){
|
||||||
|
|
||||||
|
while(!BinaryStdIn.isEmpty()){
|
||||||
|
String s = BinaryStdIn.readString();
|
||||||
|
int sLen = s.length();
|
||||||
|
CircularSuffixArray cSuffixArray = new CircularSuffixArray(s);
|
||||||
|
|
||||||
|
for(int i=0;i<sLen;i++){
|
||||||
|
if (cSuffixArray.index(i)==0){
|
||||||
|
BinaryStdOut.write(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int i=0;i<sLen;i++){
|
||||||
|
if (cSuffixArray.index(i)==0)
|
||||||
|
BinaryStdOut.write(s.charAt(sLen-1));
|
||||||
|
else
|
||||||
|
BinaryStdOut.write(s.charAt(cSuffixArray.index(i)-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BinaryStdOut.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply Burrows-Wheeler inverse transform,
|
||||||
|
// reading from standard input and writing to standard output
|
||||||
|
public static void inverseTransform(){
|
||||||
|
|
||||||
|
|
||||||
|
while(!BinaryStdIn.isEmpty()){
|
||||||
|
int current = BinaryStdIn.readInt();
|
||||||
|
String s = BinaryStdIn.readString();
|
||||||
|
|
||||||
|
char[] t = s.toCharArray();
|
||||||
|
int[] next = charSort(t);
|
||||||
|
|
||||||
|
StringBuilder sBuilder = new StringBuilder();
|
||||||
|
for(int i=0;i<t.length;i++){
|
||||||
|
sBuilder.append(t[current]);
|
||||||
|
current = next[current];
|
||||||
|
}
|
||||||
|
BinaryStdOut.write(sBuilder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryStdOut.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counting Sort for char, which also preserve the index
|
||||||
|
private static int[] charSort(char[] a) {
|
||||||
|
int n = a.length;
|
||||||
|
int R = 256; // extend ASCII alphabet size
|
||||||
|
char[] aux = new char[n];
|
||||||
|
int[] rank = new int[n];
|
||||||
|
|
||||||
|
// sort by key-indexed counting on the character
|
||||||
|
|
||||||
|
// compute frequency counts
|
||||||
|
int[] count = new int[R+1];
|
||||||
|
for (int i = 0; i < n; i++){
|
||||||
|
count[a[i] + 1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute cumulates
|
||||||
|
for (int r = 0; r < R; r++)
|
||||||
|
count[r+1] += count[r];
|
||||||
|
|
||||||
|
// move data
|
||||||
|
for (int i = 0; i < n; i++){
|
||||||
|
aux[count[a[i]]] = a[i];
|
||||||
|
rank[count[a[i]]++] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy back
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
a[i] = aux[i];
|
||||||
|
|
||||||
|
return rank;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if args[0] is "-", apply Burrows-Wheeler transform
|
||||||
|
// if args[0] is "+", apply Burrows-Wheeler inverse transform
|
||||||
|
public static void main(String[] args){
|
||||||
|
if (args[0].equals("-"))
|
||||||
|
transform();
|
||||||
|
else if (args[0].equals("+"))
|
||||||
|
inverseTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
public class CircularSuffixArray {
|
||||||
|
private final int sLen;
|
||||||
|
private int[] rank;
|
||||||
|
|
||||||
|
// circular suffix array of s
|
||||||
|
public CircularSuffixArray(String s){
|
||||||
|
if (s==null)
|
||||||
|
throw new IllegalArgumentException("String is null");
|
||||||
|
sLen = s.length();
|
||||||
|
|
||||||
|
if (sLen>0){
|
||||||
|
rank = (new Quick3Suffix()).sort(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// length of s
|
||||||
|
public int length(){
|
||||||
|
return sLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns index of ith sorted suffix
|
||||||
|
public int index(int i){
|
||||||
|
if(i<0 || i>= sLen)
|
||||||
|
throw new IllegalArgumentException("Index out of range");
|
||||||
|
|
||||||
|
return rank[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort on the possible circular suffixes
|
||||||
|
// There is no String on the suffixes
|
||||||
|
// The shift in the original string represented with an int
|
||||||
|
// During sorting, the shifts representing the suffixes
|
||||||
|
// are moved around
|
||||||
|
// This is a variant of the Quick3String for n*Log(n) performance
|
||||||
|
// LSD is too slow for long string
|
||||||
|
private class Quick3Suffix {
|
||||||
|
|
||||||
|
private static final int CUTOFF = 15; // cutoff to insertion sort
|
||||||
|
|
||||||
|
public int[] sort(String a) {
|
||||||
|
int[] shifts = new int[sLen];
|
||||||
|
for(int i=0;i<sLen;i++)
|
||||||
|
shifts[i] = i;
|
||||||
|
sort(a, 0, a.length()-1, 0, shifts);
|
||||||
|
return shifts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int charAt(String s, int d, int shift) {
|
||||||
|
assert d >= 0 && d <= s.length();
|
||||||
|
if (d == s.length()) return -1;
|
||||||
|
return s.charAt((d+shift)%sLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3-way string quicksort a[lo..hi] starting at dth character
|
||||||
|
private void sort(String a, int lo, int hi, int d, int[] shifts) {
|
||||||
|
|
||||||
|
// cutoff to insertion sort for small subarrays
|
||||||
|
if (hi <= lo + CUTOFF) {
|
||||||
|
insertion(a, lo, hi, d, shifts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lt = lo, gt = hi;
|
||||||
|
int v = charAt(a, d, shifts[lo]);
|
||||||
|
int i = lo + 1;
|
||||||
|
while (i <= gt) {
|
||||||
|
int t = charAt(a, d, shifts[i]);
|
||||||
|
if (t < v) exch(shifts, lt++, i++);
|
||||||
|
else if (t > v) exch(shifts, i, gt--);
|
||||||
|
else i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a[lo..lt-1] < v = a[lt..gt] < a[gt+1..hi].
|
||||||
|
sort(a, lo, lt-1, d, shifts);
|
||||||
|
if (v >= 0) sort(a, lt, gt, d+1, shifts);
|
||||||
|
sort(a, gt+1, hi, d, shifts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertion(String a, int lo, int hi, int d, int[] shifts) {
|
||||||
|
for (int i = lo; i <= hi; i++)
|
||||||
|
for (int j = i; j > lo && less(a, shifts[j], shifts[j-1], d); j--)
|
||||||
|
exch(shifts, j, j-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exch(int[] shifts, int i, int j) {
|
||||||
|
int temp = shifts[i];
|
||||||
|
shifts[i] = shifts[j];
|
||||||
|
shifts[j] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean less(String a, int shift_v, int shift_w, int d) {
|
||||||
|
for (int i = d; i < sLen; i++) {
|
||||||
|
if (charAt(a, i, shift_v) < charAt(a, i, shift_w)) return true;
|
||||||
|
if (charAt(a, i, shift_v) > charAt(a, i, shift_w)) return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unit testing (required)
|
||||||
|
public static void main(String[] args){
|
||||||
|
CircularSuffixArray sArray = new CircularSuffixArray("ABRACADABRA!");
|
||||||
|
|
||||||
|
int sLen = sArray.length();
|
||||||
|
for(int i=0;i<sLen;i++){
|
||||||
|
System.out.print(i);
|
||||||
|
System.out.print(" ");
|
||||||
|
/*System.out.print(originalSuffix[i]);
|
||||||
|
System.out.print(" ");
|
||||||
|
System.out.print(originalSuffix[sorter.rank[i]]);
|
||||||
|
System.out.print(" ");*/
|
||||||
|
System.out.println(sArray.index(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
import edu.princeton.cs.algs4.BinaryStdIn;
|
||||||
|
import edu.princeton.cs.algs4.BinaryStdOut;
|
||||||
|
|
||||||
|
public class MoveToFront {
|
||||||
|
private static final int EXTENDED_ASCII = 256;
|
||||||
|
// Need two arrays: one for the char, one for the rank
|
||||||
|
|
||||||
|
// apply move-to-front encoding, reading from standard input and writing to standard output
|
||||||
|
public static void encode(){
|
||||||
|
char[] characters = new char[EXTENDED_ASCII];
|
||||||
|
int[] rank = new int[EXTENDED_ASCII];
|
||||||
|
for(int i=0;i<EXTENDED_ASCII;i++){
|
||||||
|
characters[i] = (char)i;
|
||||||
|
rank[i] = i;
|
||||||
|
}
|
||||||
|
//BinaryStdIn binIn = new BinaryStdIn();
|
||||||
|
//BinaryStdOut binOut = new BinaryStdOut();
|
||||||
|
while(!BinaryStdIn.isEmpty()){
|
||||||
|
char c = BinaryStdIn.readChar();
|
||||||
|
// Search the index
|
||||||
|
int ind = rank[c];
|
||||||
|
BinaryStdOut.write(ind, 8);
|
||||||
|
// One-by-one, shift the char back by one until at index
|
||||||
|
// Shift also the rank. All done starting from one before the index
|
||||||
|
for(int i=ind-1; i>=0;i--){
|
||||||
|
char c1 = characters[i];
|
||||||
|
rank[c1]++;
|
||||||
|
characters[i+1] = c1;
|
||||||
|
}
|
||||||
|
// Place the char in the front
|
||||||
|
characters[0] = c;
|
||||||
|
rank[c] = 0;
|
||||||
|
}
|
||||||
|
BinaryStdOut.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply move-to-front decoding, reading from standard input and writing to standard output
|
||||||
|
public static void decode(){
|
||||||
|
char[] characters = new char[EXTENDED_ASCII];
|
||||||
|
int[] rank = new int[EXTENDED_ASCII];
|
||||||
|
for(int i=0;i<EXTENDED_ASCII;i++){
|
||||||
|
characters[i] = (char)i;
|
||||||
|
rank[i] = i;
|
||||||
|
}
|
||||||
|
//BinaryIn binIn = new BinaryIn();
|
||||||
|
//BinaryOut binOut = new BinaryOut();
|
||||||
|
while(!BinaryStdIn.isEmpty()){
|
||||||
|
int ind = BinaryStdIn.readInt(8);
|
||||||
|
// Search the char
|
||||||
|
char c = characters[ind];
|
||||||
|
BinaryStdOut.write(c);
|
||||||
|
// One-by-one, shift the char back by one until at index
|
||||||
|
// Shift also the rank. All done starting from one before the index
|
||||||
|
for(int i=ind-1; i>=0;i--){
|
||||||
|
char c1 = characters[i];
|
||||||
|
rank[c1]++;
|
||||||
|
characters[i+1] = c1;
|
||||||
|
}
|
||||||
|
// Place the char in the front
|
||||||
|
characters[0] = c;
|
||||||
|
rank[c] = 0;
|
||||||
|
}
|
||||||
|
BinaryStdOut.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if args[0] is "-", apply move-to-front encoding
|
||||||
|
// if args[0] is "+", apply move-to-front decoding
|
||||||
|
public static void main(String[] args){
|
||||||
|
if (args[0].equals("-"))
|
||||||
|
encode();
|
||||||
|
else if (args[0].equals("+"))
|
||||||
|
decode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue