First Commit

master
En Yi 2019-08-30 15:03:00 +08:00
commit 1c1f5dbd17
11 changed files with 1971 additions and 0 deletions

5
.gitignore vendored 100644
View File

@ -0,0 +1,5 @@
Week*/*
!.gitignore
!Week*/src/
*.zip
*.jar

View File

@ -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));
}
}
}

248
Week1/src/SAP.java 100644
View File

@ -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);
//}
}
}

View File

@ -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"));
}
}

View File

@ -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();
}
}

View File

@ -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("");
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}
}

View File

@ -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();
}
}