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