├── 8 Puzzle ├── Board.java ├── README.md └── Solver.java ├── Baseball Elimination ├── BaseballElimination.java └── README.md ├── Boggle ├── BoggleSolver.class └── README.md ├── Burrows–Wheeler ├── BurrowsWheeler.java ├── CircularSuffixArray.java ├── MoveToFront.java └── README.md ├── Kd-Tree ├── KdTree.java ├── PointSET.java └── README.md ├── Pattern Recognition ├── BruteCollinearPoints.java ├── FastCollinearPoints.java ├── LineSegment.java ├── Point.java └── README.md ├── Percolation ├── Percolation.java ├── PercolationStats.java └── README.md ├── Queues ├── Deque.java ├── Permutation.java ├── README.md └── RandomizedQueue.java ├── README.md ├── Seam Carving ├── README.md └── SeamCarver.java └── WordNet ├── Outcast.java ├── README.md ├── SAP.java └── WordNet.java /8 Puzzle/Board.java: -------------------------------------------------------------------------------- 1 | import java.util.LinkedList; 2 | import java.util.List; 3 | 4 | public class Board { 5 | private final int[][] blocks; 6 | private final int hamming; 7 | private final int manhattan; 8 | private List neighbors; 9 | 10 | public Board(int[][] blocks) { 11 | this.blocks = new int[blocks.length][blocks.length]; 12 | 13 | int hammingScore = 0; 14 | int manhattanScore = 0; 15 | 16 | for (int i = 0; i < dimension(); i++) { 17 | for (int j = 0; j < dimension(); j++) { 18 | int block = blocks[i][j]; 19 | this.blocks[i][j] = block; 20 | 21 | if (block == 0) continue; 22 | 23 | if (block != i * dimension() + j + 1) hammingScore++; 24 | 25 | block -= 1; 26 | 27 | int blockI = block / dimension(); 28 | int blockJ = block - blockI * dimension(); 29 | int distance = Math.abs(i - blockI) + Math.abs(j - blockJ); 30 | 31 | manhattanScore += distance; 32 | } 33 | } 34 | 35 | this.hamming = hammingScore; 36 | this.manhattan = manhattanScore; 37 | } 38 | 39 | public int dimension() { 40 | return blocks[0].length; 41 | } 42 | 43 | public int hamming() { 44 | return hamming; 45 | } 46 | 47 | public int manhattan() { 48 | return manhattan; 49 | } 50 | 51 | public boolean isGoal() { 52 | return hamming() == 0; 53 | } 54 | 55 | public Board twin() { 56 | int[][] twinBlocks = blocksCopy(); 57 | 58 | if (blocks[0][0] != 0 && blocks[0][1] != 0) { 59 | twinBlocks[0][0] = blocks[0][1]; 60 | twinBlocks[0][1] = blocks[0][0]; 61 | } else { 62 | twinBlocks[1][0] = blocks[1][1]; 63 | twinBlocks[1][1] = blocks[1][0]; 64 | } 65 | 66 | return new Board(twinBlocks); 67 | } 68 | 69 | public boolean equals(Object y) { 70 | if (y == null) return false; 71 | if (this.getClass() != y.getClass()) return false; 72 | 73 | Board anotherBoard = (Board) y; 74 | 75 | if (dimension() != anotherBoard.dimension()) return false; 76 | 77 | for (int i = 0; i < dimension(); i++) { 78 | for (int j = 0; j < dimension(); j++) { 79 | if (blocks[i][j] != anotherBoard.blocks[i][j]) return false; 80 | } 81 | } 82 | 83 | return true; 84 | } 85 | 86 | public Iterable neighbors() { 87 | if (neighbors != null) return neighbors; 88 | 89 | neighbors = new LinkedList(); 90 | 91 | int zeroI = 0; 92 | int zeroJ = 0; 93 | 94 | outerLoop: 95 | for (int i = 0; i < dimension(); i++) { 96 | for (int j = 0; j < dimension(); j++) { 97 | if (blocks[i][j] == 0) { 98 | zeroI = i; 99 | zeroJ = j; 100 | break outerLoop; 101 | } 102 | } 103 | } 104 | 105 | for (int k = 0; k < 4; k++) { 106 | int blockI = zeroI; 107 | int blockJ = zeroJ; 108 | 109 | switch (k) { 110 | case 0: blockI++; 111 | break; 112 | case 1: blockI--; 113 | break; 114 | case 2: blockJ++; 115 | break; 116 | case 3: blockJ--; 117 | break; 118 | } 119 | 120 | if (blockI < 0 || blockI >= dimension() || blockJ < 0 || blockJ >= dimension()) continue; 121 | int[][] heighborBlocks = blocksCopy(); 122 | 123 | heighborBlocks[zeroI][zeroJ] = heighborBlocks[blockI][blockJ]; 124 | heighborBlocks[blockI][blockJ] = 0; 125 | 126 | Board neighbor = new Board(heighborBlocks); 127 | neighbors.add(neighbor); 128 | } 129 | 130 | return neighbors; 131 | } 132 | 133 | public String toString() { 134 | StringBuilder stringBuilder = new StringBuilder(); 135 | stringBuilder.append(dimension()); 136 | 137 | for (int i = 0; i < dimension(); i++) { 138 | stringBuilder.append("\n"); 139 | for (int j = 0; j < dimension(); j++) { 140 | stringBuilder.append(" " + blocks[i][j]); 141 | } 142 | } 143 | 144 | return stringBuilder.toString(); 145 | } 146 | 147 | private int[][] blocksCopy() { 148 | int[][] blocksCopy = new int[dimension()][dimension()]; 149 | 150 | for (int i = 0; i < dimension(); i++) { 151 | for (int j = 0; j < dimension(); j++) { 152 | blocksCopy[i][j] = blocks[i][j]; 153 | } 154 | } 155 | 156 | return blocksCopy; 157 | } 158 | } -------------------------------------------------------------------------------- /8 Puzzle/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment: 8 Puzzle 2 | 3 | ### Write a program to solve the 8-puzzle problem (and its natural generalizations) using the A* search algorithm. 4 | 5 | Your goal is to rearrange the blocks so that they are in order, using as few moves as possible. You are permitted to slide blocks horizontally or vertically into the blank square. 6 | 7 | __Performance requirements.__ 8 | 9 | Your implementation should support all Board methods in time proportional to n2 (or better) in the worst case. -------------------------------------------------------------------------------- /8 Puzzle/Solver.java: -------------------------------------------------------------------------------- 1 | import java.util.Deque; 2 | import java.util.LinkedList; 3 | import java.util.List; 4 | import edu.princeton.cs.algs4.MinPQ; 5 | import edu.princeton.cs.algs4.In; 6 | import edu.princeton.cs.algs4.StdOut; 7 | 8 | public class Solver { 9 | private final SearchNode solutionNode; 10 | 11 | private class SearchNode implements Comparable { 12 | public final Board board; 13 | public final SearchNode predecessor; 14 | public final int moves; 15 | public final int priority; 16 | 17 | public SearchNode(Board board, SearchNode predecessor) { 18 | this.board = board; 19 | this.predecessor = predecessor; 20 | this.moves = predecessor == null ? 0 : predecessor.moves + 1; 21 | this.priority = board.manhattan() + moves; 22 | 23 | } 24 | 25 | public void insertNeighbors(MinPQ priorityQueue) { 26 | for (Board neighbor : board.neighbors()) { 27 | if (predecessor != null && neighbor.equals(predecessor.board)) continue; 28 | 29 | SearchNode node = new SearchNode(neighbor, this); 30 | priorityQueue.insert(node); 31 | } 32 | } 33 | 34 | public int compareTo(SearchNode that) { 35 | return this.priority - that.priority; 36 | } 37 | } 38 | 39 | public Solver(Board initial) { 40 | if (initial == null) throw new IllegalArgumentException(); 41 | 42 | MinPQ solutionPQ = new MinPQ(); 43 | MinPQ twinPQ = new MinPQ(); 44 | 45 | SearchNode initialNode = new SearchNode(initial, null); 46 | solutionPQ.insert(initialNode); 47 | 48 | SearchNode initialTwinNode = new SearchNode(initial.twin(), null); 49 | twinPQ.insert(initialTwinNode); 50 | 51 | while (true) { 52 | SearchNode solutionNode = solutionPQ.delMin(); 53 | SearchNode twinNode = twinPQ.delMin(); 54 | 55 | if (solutionNode.board.isGoal()) { 56 | this.solutionNode = solutionNode; 57 | break; 58 | } else if (twinNode.board.isGoal()) { 59 | this.solutionNode = null; 60 | break; 61 | } 62 | 63 | solutionNode.insertNeighbors(solutionPQ); 64 | twinNode.insertNeighbors(twinPQ); 65 | } 66 | } 67 | 68 | public boolean isSolvable() { 69 | return solutionNode != null; 70 | } 71 | 72 | public int moves() { 73 | if (isSolvable()) { 74 | return solutionNode.moves; 75 | } else { 76 | return -1; 77 | } 78 | } 79 | 80 | public Iterable solution() { 81 | if (isSolvable()) { 82 | Deque solution = new LinkedList<>(); 83 | SearchNode nextNode = solutionNode; 84 | while (nextNode != null) { 85 | solution.addFirst(nextNode.board); 86 | nextNode = nextNode.predecessor; 87 | } 88 | 89 | return solution; 90 | } else { 91 | return null; 92 | } 93 | } 94 | 95 | public static void main(String[] args) { 96 | // create initial board from file 97 | In in = new In(args[0]); 98 | int n = in.readInt(); 99 | int[][] blocks = new int[n][n]; 100 | for (int i = 0; i < n; i++) 101 | for (int j = 0; j < n; j++) 102 | blocks[i][j] = in.readInt(); 103 | Board initial = new Board(blocks); 104 | 105 | // solve the puzzle 106 | Solver solver = new Solver(initial); 107 | 108 | // print solution to standard output 109 | if (!solver.isSolvable()) 110 | StdOut.println("No solution possible"); 111 | else { 112 | StdOut.println("Minimum number of moves = " + solver.moves()); 113 | for (Board board : solver.solution()) { 114 | StdOut.println(board); 115 | } 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /Baseball Elimination/BaseballElimination.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.FordFulkerson; 2 | import edu.princeton.cs.algs4.FlowEdge; 3 | import edu.princeton.cs.algs4.FlowNetwork; 4 | import edu.princeton.cs.algs4.In; 5 | import edu.princeton.cs.algs4.StdOut; 6 | import java.util.HashMap; 7 | import java.util.HashSet; 8 | 9 | public class BaseballElimination { 10 | private static final int SOURCE_INDEX = 0; 11 | private static final int SINK_INDEX = 1; 12 | 13 | private final HashMap teamsMap; 14 | private final String[] teams; 15 | private final int[] wins; 16 | private final int[] losses; 17 | private final int[] remaining; 18 | private final int[][] against; 19 | private final HashMap> eliminationMap; 20 | 21 | // create a baseball division from given filename in format specified below 22 | public BaseballElimination(String filename) { 23 | In in = new In(filename); 24 | int teamsCount = in.readInt(); 25 | 26 | this.teamsMap = new HashMap<>(); 27 | this.teams = new String[teamsCount]; 28 | this.wins = new int[teamsCount]; 29 | this.losses = new int[teamsCount]; 30 | this.remaining = new int[teamsCount]; 31 | this.against = new int[teamsCount][teamsCount]; 32 | this.eliminationMap = new HashMap<>(); 33 | 34 | for (int i = 0; i < teamsCount; i++) { 35 | String teamName = in.readString(); 36 | 37 | this.teamsMap.put(teamName, i); 38 | this.teams[i] = teamName; 39 | 40 | this.wins[i] = in.readInt(); 41 | this.losses[i] = in.readInt(); 42 | this.remaining[i] = in.readInt(); 43 | 44 | for (int j = 0; j < teamsCount; j++) { 45 | this.against[i][j] = in.readInt(); 46 | } 47 | } 48 | } 49 | 50 | // number of teams 51 | public int numberOfTeams() { 52 | return teams.length; 53 | } 54 | 55 | // all teams 56 | public Iterable teams() { 57 | return this.teamsMap.keySet(); 58 | } 59 | 60 | // number of wins for given team 61 | public int wins(String team) { 62 | return this.wins[this.teamIndex(team)]; 63 | } 64 | 65 | // number of losses for given team 66 | public int losses(String team) { 67 | return this.losses[this.teamIndex(team)]; 68 | } 69 | 70 | // number of remaining games for given team 71 | public int remaining(String team) { 72 | return this.remaining[this.teamIndex(team)]; 73 | } 74 | 75 | // number of remaining games between team1 and team2 76 | public int against(String team1, String team2) { 77 | return this.against[this.teamIndex(team1)][this.teamIndex(team2)]; 78 | } 79 | 80 | private Integer teamIndex(String team) { 81 | Integer teamIndex = this.teamsMap.get(team); 82 | if (teamIndex == null) { 83 | throw new IllegalArgumentException(); 84 | } 85 | 86 | return teamIndex; 87 | } 88 | 89 | // is given team eliminated? 90 | public boolean isEliminated(String team) { 91 | return !eliminationSet(team).isEmpty(); 92 | } 93 | 94 | // subset R of teams that eliminates given team; null if not eliminated 95 | public Iterable certificateOfElimination(String team) { 96 | return isEliminated(team) ? eliminationSet(team) : null; 97 | } 98 | 99 | public static void main(String[] args) { 100 | BaseballElimination division = new BaseballElimination(args[0]); 101 | for (String team : division.teams()) { 102 | if (division.isEliminated(team)) { 103 | StdOut.print(team + " is eliminated by the subset R = { "); 104 | for (String t : division.certificateOfElimination(team)) { 105 | StdOut.print(t + " "); 106 | } 107 | StdOut.println("}"); 108 | } 109 | else { 110 | StdOut.println(team + " is not eliminated"); 111 | } 112 | } 113 | } 114 | 115 | private HashSet eliminationSet(String team) { 116 | if (this.teamsMap.get(team) == null) { 117 | throw new IllegalArgumentException(); 118 | } 119 | 120 | if (this.eliminationMap.get(team) == null) { 121 | if (!trivialElimination(team)) { 122 | calculateElimination(team); 123 | } 124 | } 125 | 126 | return this.eliminationMap.get(team); 127 | } 128 | 129 | private boolean trivialElimination(String team) { 130 | Integer teamIndex = this.teamIndex(team); 131 | int maxWins = this.wins[teamIndex] + this.remaining[teamIndex]; 132 | HashSet eliminatingTeams = new HashSet<>(); 133 | 134 | for (int i = 0; i < this.numberOfTeams(); i++) { 135 | if (i == teamIndex) continue; 136 | 137 | if (maxWins < wins[i]) { 138 | eliminatingTeams.add(this.teams[i]); 139 | } 140 | } 141 | 142 | this.eliminationMap.put(team, eliminatingTeams); 143 | 144 | return !eliminatingTeams.isEmpty(); 145 | } 146 | 147 | private void calculateElimination(String team) { 148 | int teamIndex = teamIndex(team); 149 | int teamsCount = this.teams.length; 150 | int opponentTeams = teamsCount - 1; 151 | int totalGames = teamsCount * opponentTeams; 152 | int uniqueGames = totalGames / 2; 153 | int opponentsGames = uniqueGames - opponentTeams; 154 | 155 | int edgesCount = 2 + opponentsGames + opponentTeams; 156 | 157 | FlowNetwork network = new FlowNetwork(edgesCount); 158 | 159 | int gameEdgeIndex = opponentTeams + 2; 160 | 161 | int maxWins = this.wins[teamIndex] + this.remaining[teamIndex]; 162 | 163 | for (int i = 0; i < this.numberOfTeams(); i++) { 164 | if (i == teamIndex) continue; 165 | 166 | int opponentIndex = i < teamIndex ? i + 2 : i + 1; 167 | FlowEdge teamToSinkEdge = new FlowEdge(opponentIndex, SINK_INDEX, maxWins - this.wins[i]); 168 | network.addEdge(teamToSinkEdge); 169 | 170 | for (int j = 0; j < i; j++) { 171 | if (j == teamIndex) continue; 172 | 173 | int gamesCount = this.against[i][j]; 174 | 175 | FlowEdge sourceToGameEdge = new FlowEdge(SOURCE_INDEX, gameEdgeIndex, gamesCount); 176 | network.addEdge(sourceToGameEdge); 177 | 178 | FlowEdge team1WinEdge = new FlowEdge(gameEdgeIndex, opponentIndex, Double.POSITIVE_INFINITY); 179 | network.addEdge(team1WinEdge); 180 | 181 | int team2Index = j < teamIndex ? j + 2 : j + 1; 182 | FlowEdge team2WinEdge = new FlowEdge(gameEdgeIndex, team2Index, Double.POSITIVE_INFINITY); 183 | network.addEdge(team2WinEdge); 184 | 185 | gameEdgeIndex++; 186 | } 187 | } 188 | 189 | FordFulkerson maxFlow = new FordFulkerson(network, SOURCE_INDEX, SINK_INDEX); 190 | HashSet eliminatingTeams = new HashSet<>(); 191 | 192 | for (int i = 0; i < this.numberOfTeams(); i++) { 193 | if (i == teamIndex) continue; 194 | 195 | int opponentIndex = i < teamIndex ? i + 2 : i + 1; 196 | 197 | if (maxFlow.inCut(opponentIndex)) { 198 | eliminatingTeams.add(teams[i]); 199 | } 200 | } 201 | 202 | this.eliminationMap.put(team, eliminatingTeams); 203 | } 204 | } -------------------------------------------------------------------------------- /Baseball Elimination/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment 3: Baseball Elimination 2 | 3 | [Assignment Specification](http://coursera.cs.princeton.edu/algs4/assignments/baseball.html) 4 | 5 | ### The baseball elimination problem. In the baseball elimination problem, there is a division consisting of n teams. At some point during the season, team i has w[i] wins, l[i] losses, r[i] remaining games, and g[i][j] games left to play against team j. A team is mathematically eliminated if it cannot possibly finish the season in (or tied for) first place. The goal is to determine exactly which teams are mathematically eliminated. For simplicity, we assume that no games end in a tie (as is the case in Major League Baseball) and that there are no rainouts (i.e., every scheduled game is played). -------------------------------------------------------------------------------- /Boggle/BoggleSolver.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SergeyKuryanov/Coursera-Algorithms/a29f857aa0dcdf63174be624ad0d09bbddb3370e/Boggle/BoggleSolver.class -------------------------------------------------------------------------------- /Boggle/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment 4: Boggle 2 | 3 | [Assignment Specification](http://coursera.cs.princeton.edu/algs4/assignments/boggle.html) 4 | 5 | ### Write a program to play the word game Boggle®. 6 | 7 | The Boggle game. Boggle is a word game designed by Allan Turoff and distributed by Hasbro. It involves a board made up of 16 cubic dice, where each die has a letter printed on each of its 6 sides. At the beginning of the game, the 16 dice are shaken and randomly distributed into a 4-by-4 tray, with only the top sides of the dice visible. The players compete to accumulate points by building valid words from the dice, according to these rules: 8 | 9 | - A valid word must be composed by following a sequence of adjacent dice—two dice are adjacent if they are horizontal, vertical, or diagonal neighbors. 10 | - A valid word can use each die at most once. 11 | - A valid word must contain at least 3 letters. 12 | - A valid word must be in the dictionary (which typically does not contain proper nouns). 13 | 14 | __Performance.__ If you choose your data structures and algorithms judiciously, your program can preprocess the dictionary and find all valid words in a random Hasbro board (or even a random 10-by-10 board) in a fraction of a second. To stress test the performance of your implementation, create one BoggleSolver object (from a given dictionary); then, repeatedly generate and solve random Hasbro boards. How many random Hasbro boards can you solve per second? For full credit, your program must be able to solve thousands of random Hasbro boards per second. The goal on this assignment is raw speed—for example, it's fine to use 10× more memory if the program is 10× faster. -------------------------------------------------------------------------------- /Burrows–Wheeler/BurrowsWheeler.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.BinaryStdIn; 2 | import edu.princeton.cs.algs4.BinaryStdOut; 3 | 4 | public class BurrowsWheeler { 5 | private static final int R = 256; 6 | 7 | // apply Burrows-Wheeler transform, reading from standard input and writing to standard output 8 | public static void transform() { 9 | while (!BinaryStdIn.isEmpty()) { 10 | String string = BinaryStdIn.readString(); 11 | 12 | CircularSuffixArray suffixArray = new CircularSuffixArray(string); 13 | 14 | for (int i = 0; i < suffixArray.length(); i++) { 15 | if (suffixArray.index(i) == 0) { 16 | BinaryStdOut.write(i); 17 | break; 18 | } 19 | } 20 | 21 | for (int i = 0; i < suffixArray.length(); i++) { 22 | int index = suffixArray.index(i) - 1; 23 | if (index < 0) index = string.length() - 1; 24 | 25 | BinaryStdOut.write(string.charAt(index)); 26 | } 27 | } 28 | 29 | BinaryStdIn.close(); 30 | BinaryStdOut.close(); 31 | } 32 | 33 | // apply Burrows-Wheeler inverse transform, reading from standard input and writing to standard output 34 | public static void inverseTransform() { 35 | while (!BinaryStdIn.isEmpty()) { 36 | int first = BinaryStdIn.readInt(); 37 | String string = BinaryStdIn.readString(); 38 | 39 | char[] t = string.toCharArray(); 40 | int[] next = new int[t.length]; 41 | char[] sorted = new char[t.length]; 42 | int[] counts = new int[R + 1]; 43 | 44 | for (int i = 0; i < t.length; i++) { 45 | counts[t[i] + 1]++; 46 | } 47 | 48 | for (int r = 0; r < R; r++) { 49 | counts[r + 1] += counts[r]; 50 | } 51 | 52 | for (int i = 0; i < t.length; i++) { 53 | sorted[counts[t[i]]++] = t[i]; 54 | } 55 | 56 | counts = new int[R + 1]; 57 | for (int i = 0; i < t.length; i++) { 58 | counts[sorted[i] + 1]++; 59 | } 60 | 61 | for (int r = 0; r < R; r++) { 62 | counts[r + 1] += counts[r]; 63 | } 64 | 65 | for (int j = 0; j < t.length; j++) { 66 | int i = counts[t[j]]++; 67 | next[i] = j; 68 | } 69 | 70 | for (int i = 0, index = first; i < t.length; i++, index = next[index]) { 71 | BinaryStdOut.write(sorted[index]); 72 | } 73 | } 74 | 75 | BinaryStdIn.close(); 76 | BinaryStdOut.close(); 77 | } 78 | 79 | // if args[0] is '-', apply Burrows-Wheeler transform 80 | // if args[0] is '+', apply Burrows-Wheeler inverse transform 81 | public static void main(String[] args) { 82 | if (args[0].equals("-")) transform(); 83 | else if (args[0].equals("+")) inverseTransform(); 84 | else throw new IllegalArgumentException(); 85 | } 86 | } -------------------------------------------------------------------------------- /Burrows–Wheeler/CircularSuffixArray.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.StdOut; 2 | import java.util.Arrays; 3 | import java.util.Comparator; 4 | 5 | public class CircularSuffixArray { 6 | private final String string; 7 | private final Integer[] indices; 8 | 9 | // circular suffix array of s 10 | public CircularSuffixArray(String s) { 11 | if (s == null) { 12 | throw new java.lang.IllegalArgumentException(); 13 | } 14 | 15 | this.string = s; 16 | 17 | Integer[] indices = new Integer[s.length()]; 18 | for (Integer i = 0; i < indices.length; i++) { 19 | indices[i] = i; 20 | } 21 | 22 | Arrays.sort(indices, suffixOrder()); 23 | this.indices = indices; 24 | } 25 | 26 | // length of s 27 | public int length() { 28 | return string.length(); 29 | } 30 | 31 | // returns index of ith sorted suffix 32 | public int index(int i) { 33 | if (i < 0 || i >= this.indices.length) { 34 | throw new java.lang.IllegalArgumentException(); 35 | } 36 | 37 | return this.indices[i]; 38 | } 39 | 40 | // unit testing (required) 41 | public static void main(String[] args) { 42 | CircularSuffixArray suffixArray = new CircularSuffixArray(args[0]); 43 | for (int i = 0; i < suffixArray.length(); i++) { 44 | StdOut.print(suffixArray.index(i) + " "); 45 | } 46 | 47 | StdOut.println(""); 48 | } 49 | 50 | private Comparator suffixOrder() { 51 | return new Comparator() { 52 | @Override 53 | public int compare(Integer first, Integer second) { 54 | for (int i = 0; i < string.length(); i++) { 55 | int index1 = (first + i) % string.length(); 56 | int index2 = (second + i) % string.length(); 57 | int result = string.charAt(index1) - string.charAt(index2); 58 | if (result != 0) { return result; } 59 | } 60 | 61 | return 0; 62 | } 63 | }; 64 | } 65 | } -------------------------------------------------------------------------------- /Burrows–Wheeler/MoveToFront.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.BinaryStdIn; 2 | import edu.princeton.cs.algs4.BinaryStdOut; 3 | 4 | public class MoveToFront { 5 | private static final int R = 256; 6 | 7 | // apply move-to-front encoding, reading from standard input and writing to standard output 8 | public static void encode() { 9 | char[] sequence = createSequence(); 10 | 11 | while (!BinaryStdIn.isEmpty()) { 12 | char c = BinaryStdIn.readChar(); 13 | int i = 0; 14 | 15 | for (i = 0; i < sequence.length; i++) { 16 | if (sequence[i] == c) break; 17 | } 18 | 19 | BinaryStdOut.write((char) i); 20 | sequence = moveToFront(sequence, c, i); 21 | } 22 | 23 | BinaryStdIn.close(); 24 | BinaryStdOut.close(); 25 | } 26 | 27 | // apply move-to-front decoding, reading from standard input and writing to standard output 28 | public static void decode() { 29 | char[] sequence = createSequence(); 30 | 31 | while (!BinaryStdIn.isEmpty()) { 32 | int i = BinaryStdIn.readChar(); 33 | char c = sequence[i]; 34 | BinaryStdOut.write(c); 35 | 36 | sequence = moveToFront(sequence, c, i); 37 | } 38 | 39 | BinaryStdIn.close(); 40 | BinaryStdOut.close(); 41 | } 42 | 43 | private static char[] createSequence() { 44 | char[] sequence = new char[R]; 45 | for (int i = 0; i < R; i++) { 46 | sequence[i] = (char) i; 47 | } 48 | 49 | return sequence; 50 | } 51 | 52 | private static char[] moveToFront(char[] sequence, char c, int i) { 53 | for (int j = i; j > 0; j--) { 54 | sequence[j] = sequence[j - 1]; 55 | } 56 | 57 | sequence[0] = c; 58 | 59 | return sequence; 60 | } 61 | 62 | // if args[0] is '-', apply move-to-front encoding 63 | // if args[0] is '+', apply move-to-front decoding 64 | public static void main(String[] args) { 65 | if (args[0].equals("-")) encode(); 66 | else if (args[0].equals("+")) decode(); 67 | else throw new IllegalArgumentException(); 68 | } 69 | } -------------------------------------------------------------------------------- /Burrows–Wheeler/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment 5: Burrows–Wheeler Data Compression 2 | 3 | [Assignment Specification](http://coursera.cs.princeton.edu/algs4/assignments/burrows.html) 4 | 5 | ### Implement the Burrows–Wheeler data compression algorithm. This revolutionary algorithm outcompresses gzip and PKZIP, is relatively easy to implement, and is not protected by any patents. It forms the basis of the Unix compression utility bzip2. 6 | 7 | The Burrows–Wheeler compression algorithm consists of three algorithmic components, which are applied in succession: 8 | 9 | __Burrows–Wheeler transform.__ Given a typical English text file, transform it into a text file in which sequences of the same character occur near each other many times. 10 | Move-to-front encoding. Given a text file in which sequences of the same character occur near each other many times, convert it into a text file in which certain characters appear more frequently than others. 11 | 12 | __Huffman compression.__ Given a text file in which certain characters appear more frequently than others, compress it by encoding frequently occurring characters with short codewords and infrequently occurring characters with long codewords. 13 | 14 | __Step 3__ is the one that compresses the message: it is particularly effective because Steps 1 and 2 produce a text file in which certain characters appear much more frequently than others. To expand a message, apply the inverse operations in reverse order: first apply the Huffman expansion, then the move-to-front decoding, and finally the inverse Burrows–Wheeler transform. Your task is to implement the Burrows–Wheeler and move-to-front components. -------------------------------------------------------------------------------- /Kd-Tree/KdTree.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.Point2D; 2 | import edu.princeton.cs.algs4.RectHV; 3 | import edu.princeton.cs.algs4.StdDraw; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | public class KdTree { 8 | private Node root = null; 9 | private int size = 0; 10 | private Point2D nearestPoint = null; 11 | 12 | private class Node { 13 | private final Point2D point; 14 | private Node left; 15 | private Node right; 16 | private final boolean isVertical; 17 | private final RectHV rect; 18 | 19 | public Node(Point2D point, boolean isVertical, Node parent) { 20 | this.point = point; 21 | this.isVertical = isVertical; 22 | 23 | if (parent == null) { 24 | this.rect = new RectHV(0, 0, 1, 1); 25 | } else { 26 | double minX = parent.rect.xmin(); 27 | double minY = parent.rect.ymin(); 28 | double maxX = parent.rect.xmax(); 29 | double maxY = parent.rect.ymax(); 30 | 31 | int result = parent.compareTo(point); 32 | 33 | if (isVertical) { 34 | if (result > 0) { 35 | maxY = parent.point.y(); 36 | } else { 37 | minY = parent.point.y(); 38 | } 39 | } else { 40 | if (result > 0) { 41 | maxX = parent.point.x(); 42 | } else { 43 | minX = parent.point.x(); 44 | } 45 | } 46 | 47 | this.rect = new RectHV(minX, minY, maxX, maxY); 48 | } 49 | } 50 | 51 | public int compareTo(Point2D that) { 52 | if (isVertical) { 53 | return Double.compare(this.point.x(), that.x()); 54 | } else { 55 | return Double.compare(this.point.y(), that.y()); 56 | } 57 | } 58 | 59 | public void draw() { 60 | StdDraw.setPenRadius(0.005); 61 | 62 | if (isVertical) { 63 | StdDraw.setPenColor(StdDraw.RED); 64 | StdDraw.line(point.x(), rect.ymin(), point.x(), rect.ymax()); 65 | } else { 66 | StdDraw.setPenColor(StdDraw.BLUE); 67 | StdDraw.line(rect.xmin(), point.y(), rect.xmax(), point.y()); 68 | } 69 | 70 | StdDraw.setPenRadius(0.03); 71 | StdDraw.setPenColor(StdDraw.BLACK); 72 | point.draw(); 73 | 74 | if (left != null) { 75 | left.draw(); 76 | } 77 | 78 | if (right != null) { 79 | right.draw(); 80 | } 81 | } 82 | } 83 | 84 | public KdTree() { 85 | } 86 | 87 | public boolean isEmpty() { 88 | return size == 0; 89 | } 90 | 91 | public int size() { 92 | return size; 93 | } 94 | 95 | public void insert(Point2D p) { 96 | if (p == null) throw new IllegalArgumentException(); 97 | 98 | root = put(root, p, true, null); 99 | } 100 | 101 | private Node put(Node node, Point2D point, boolean isVertical, Node previous) { 102 | if (node == null) { 103 | size++; 104 | return new Node(point, isVertical, previous); 105 | } 106 | 107 | if (node.point.compareTo(point) == 0) return node; 108 | 109 | if (node.compareTo(point) > 0) { 110 | node.left = put(node.left, point, !isVertical, node); 111 | } else { 112 | node.right = put(node.right, point, !isVertical, node); 113 | } 114 | 115 | return node; 116 | } 117 | 118 | public boolean contains(Point2D p) { 119 | if (p == null) throw new IllegalArgumentException(); 120 | 121 | return get(root, p) != null; 122 | } 123 | 124 | private Node get(Node node, Point2D point) { 125 | if (node == null) return null; 126 | 127 | if (node.point.equals(point)) return node; 128 | 129 | if (node.compareTo(point) > 0) { 130 | return get(node.left, point); 131 | } else { 132 | return get(node.right, point); 133 | } 134 | } 135 | 136 | public void draw() { 137 | if (root != null) { 138 | root.draw(); 139 | } 140 | } 141 | 142 | public Iterable range(RectHV rect) { 143 | if (rect == null) throw new IllegalArgumentException(); 144 | 145 | return range(root, rect, new LinkedList()); 146 | } 147 | 148 | private List range(Node node, RectHV rect, List points) { 149 | if (node == null) return points; 150 | 151 | if (node.rect.intersects(rect)) { 152 | if (rect.contains(node.point)) { 153 | points.add(node.point); 154 | } 155 | 156 | range(node.left, rect, points); 157 | range(node.right, rect, points); 158 | } 159 | 160 | return points; 161 | } 162 | 163 | public Point2D nearest(Point2D p) { 164 | if (p == null) throw new IllegalArgumentException(); 165 | 166 | if (isEmpty()) return null; 167 | 168 | nearestPoint = root.point; 169 | nearestPoint(root, p); 170 | 171 | return nearestPoint; 172 | } 173 | 174 | private void nearestPoint(Node node, Point2D point) { 175 | if (node == null) return; 176 | 177 | if (node.rect.distanceSquaredTo(point) < nearestPoint.distanceSquaredTo(point)) { 178 | updateNearestPointIfNeeded(point, node.point); 179 | 180 | if (node.compareTo(point) > 0) { 181 | nearestPoint(node.left, point); 182 | nearestPoint(node.right, point); 183 | } else { 184 | nearestPoint(node.right, point); 185 | nearestPoint(node.left, point); 186 | } 187 | } 188 | } 189 | 190 | private boolean updateNearestPointIfNeeded(Point2D targetPoint, Point2D newPoint) { 191 | if (nearestPoint == null) { 192 | nearestPoint = newPoint; 193 | return true; 194 | } 195 | 196 | double distanceToNearest = targetPoint.distanceSquaredTo(nearestPoint); 197 | double distanceToNew = targetPoint.distanceSquaredTo(newPoint); 198 | 199 | if (distanceToNew < distanceToNearest) { 200 | nearestPoint = newPoint; 201 | return true; 202 | } 203 | 204 | return false; 205 | } 206 | } -------------------------------------------------------------------------------- /Kd-Tree/PointSET.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.Point2D; 2 | import edu.princeton.cs.algs4.RectHV; 3 | import edu.princeton.cs.algs4.SET; 4 | 5 | public class PointSET { 6 | private final SET points; 7 | 8 | public PointSET() { 9 | points = new SET(); 10 | } 11 | 12 | public boolean isEmpty() { 13 | return points.isEmpty(); 14 | } 15 | 16 | public int size() { 17 | return points.size(); 18 | } 19 | 20 | public void insert(Point2D p) { 21 | if (p == null) throw new IllegalArgumentException(); 22 | 23 | points.add(p); 24 | } 25 | 26 | public boolean contains(Point2D p) { 27 | if (p == null) throw new IllegalArgumentException(); 28 | 29 | return points.contains(p); 30 | } 31 | 32 | public void draw() { 33 | for (Point2D point: points) { 34 | point.draw(); 35 | } 36 | } 37 | 38 | public Iterable range(RectHV rect) { 39 | if (rect == null) throw new IllegalArgumentException(); 40 | 41 | SET rangePoints = new SET(); 42 | for (Point2D point: points) { 43 | if (rect.contains(point)) { 44 | rangePoints.add(point); 45 | } 46 | } 47 | return rangePoints; 48 | } 49 | 50 | public Point2D nearest(Point2D p) { 51 | if (p == null) throw new IllegalArgumentException(); 52 | 53 | if (isEmpty()) return null; 54 | 55 | Point2D nearestPoint = null; 56 | 57 | for (Point2D point: points) { 58 | if (nearestPoint == null) { 59 | nearestPoint = point; 60 | continue; 61 | } 62 | 63 | if (p.distanceSquaredTo(point) < p.distanceSquaredTo(nearestPoint)) { 64 | nearestPoint = point; 65 | } 66 | } 67 | 68 | return nearestPoint; 69 | } 70 | } -------------------------------------------------------------------------------- /Kd-Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment: Kd-Trees 2 | 3 | ### Write a data type to represent a set of points in the unit square. 4 | 5 | All points have x- and y-coordinates between 0 and 1. Implement data type using a 2d-tree to support efficient range search (find all of the points contained in a query rectangle) and nearest-neighbor search (find a closest point to a query point). 2d-trees have numerous applications, ranging from classifying astronomical objects to computer animation to speeding up neural networks to mining data to image retrieval. 6 | 7 | __Performance requirements.__ 8 | 9 | Your implementation should support insert() and contains() in time proportional to the logarithm of the number of points in the set in the worst case; it should support nearest() and range() in time proportional to the number of points in the set. -------------------------------------------------------------------------------- /Pattern Recognition/BruteCollinearPoints.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.LinkedList; 3 | import java.util.List; 4 | import edu.princeton.cs.algs4.StdDraw; 5 | import edu.princeton.cs.algs4.In; 6 | import edu.princeton.cs.algs4.StdOut; 7 | 8 | public class BruteCollinearPoints { 9 | private LineSegment[] segments = null; 10 | 11 | public BruteCollinearPoints(Point[] points) { 12 | if (points == null) { 13 | throw new IllegalArgumentException(); 14 | } 15 | 16 | Point[] pointsCopy = new Point[points.length]; 17 | 18 | for (int i = 0; i < points.length; i++) { 19 | Point p = points[i]; 20 | 21 | if (p == null) { 22 | throw new IllegalArgumentException(); 23 | } 24 | 25 | pointsCopy[i] = p; 26 | } 27 | 28 | Arrays.sort(pointsCopy); 29 | List lineSegments = new LinkedList(); 30 | 31 | Point previousPoint = null; 32 | 33 | for (int i = 0; i < pointsCopy.length; i++) { 34 | if (previousPoint != null && pointsCopy[i].compareTo(previousPoint) == 0) { 35 | throw new IllegalArgumentException(); 36 | } else { 37 | previousPoint = pointsCopy[i]; 38 | } 39 | 40 | for (int j = i + 1; j < pointsCopy.length; j++) { 41 | for (int k = j + 1; k < pointsCopy.length; k++) { 42 | for (int l = k + 1; l < pointsCopy.length; l++) { 43 | Point p = pointsCopy[i]; 44 | Point q = pointsCopy[j]; 45 | Point r = pointsCopy[k]; 46 | Point s = pointsCopy[l]; 47 | 48 | if (Double.compare(p.slopeTo(q), p.slopeTo(r)) == 0 && Double.compare(p.slopeTo(r), p.slopeTo(s)) == 0) { 49 | LineSegment segment = new LineSegment(p, s); 50 | lineSegments.add(segment); 51 | } 52 | } 53 | } 54 | } 55 | } 56 | 57 | segments = lineSegments.toArray(new LineSegment[lineSegments.size()]); 58 | } 59 | 60 | public int numberOfSegments() { 61 | return segments.length; 62 | } 63 | 64 | public LineSegment[] segments() { 65 | return segments.clone(); 66 | } 67 | 68 | public static void main(String[] args) { 69 | 70 | // read the n points from a file 71 | In in = new In(args[0]); 72 | int n = in.readInt(); 73 | Point[] points = new Point[n]; 74 | for (int i = 0; i < n; i++) { 75 | int x = in.readInt(); 76 | int y = in.readInt(); 77 | points[i] = new Point(x, y); 78 | } 79 | 80 | // draw the points 81 | StdDraw.enableDoubleBuffering(); 82 | StdDraw.setXscale(0, 32768); 83 | StdDraw.setYscale(0, 32768); 84 | for (Point p : points) { 85 | p.draw(); 86 | } 87 | StdDraw.show(); 88 | 89 | // print and draw the line segments 90 | BruteCollinearPoints collinear = new BruteCollinearPoints(points); 91 | for (LineSegment segment : collinear.segments()) { 92 | StdOut.println(segment); 93 | segment.draw(); 94 | } 95 | StdDraw.show(); 96 | } 97 | } -------------------------------------------------------------------------------- /Pattern Recognition/FastCollinearPoints.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.LinkedList; 3 | import java.util.List; 4 | import edu.princeton.cs.algs4.StdDraw; 5 | import edu.princeton.cs.algs4.In; 6 | import edu.princeton.cs.algs4.StdOut; 7 | 8 | public class FastCollinearPoints { 9 | private LineSegment[] segments = null; 10 | 11 | public FastCollinearPoints(Point[] points) { 12 | if (points == null) { 13 | throw new IllegalArgumentException(); 14 | } 15 | 16 | Point[] pointsCopy = new Point[points.length]; 17 | 18 | for (int i = 0; i < points.length; i++) { 19 | Point p = points[i]; 20 | 21 | if (p == null) { 22 | throw new IllegalArgumentException(); 23 | } 24 | 25 | pointsCopy[i] = p; 26 | } 27 | 28 | Arrays.sort(pointsCopy); 29 | List lineSegments = new LinkedList(); 30 | 31 | Point previousPoint = null; 32 | 33 | for (int i = 0; i < pointsCopy.length; i++) { 34 | Point p = pointsCopy[i]; 35 | 36 | if (previousPoint != null && p.compareTo(previousPoint) == 0) { 37 | throw new IllegalArgumentException(); 38 | } else { 39 | previousPoint = p; 40 | } 41 | 42 | Point[] slopeOrderedPoints = pointsCopy.clone(); 43 | Arrays.sort(slopeOrderedPoints, p.slopeOrder()); 44 | 45 | double lastSlope = Double.NEGATIVE_INFINITY; 46 | int slopeStartIndex = 0; 47 | 48 | for (int j = 1; j < slopeOrderedPoints.length; j++) { 49 | Point q = slopeOrderedPoints[j]; 50 | double currentSlope = p.slopeTo(q); 51 | 52 | boolean lastPoint = j == slopeOrderedPoints.length - 1; 53 | 54 | if (Double.compare(currentSlope, lastSlope) != 0) { 55 | if (j - slopeStartIndex >= 3) { 56 | if (p.compareTo(slopeOrderedPoints[slopeStartIndex]) <= 0) { 57 | LineSegment segment = new LineSegment(p, slopeOrderedPoints[j - 1]); 58 | lineSegments.add(segment); 59 | } 60 | } 61 | 62 | slopeStartIndex = j; 63 | } else if (lastPoint) { 64 | if (j - slopeStartIndex >= 2) { 65 | if (p.compareTo(slopeOrderedPoints[slopeStartIndex]) <= 0) { 66 | LineSegment segment = new LineSegment(p, q); 67 | lineSegments.add(segment); 68 | } 69 | } 70 | } 71 | 72 | lastSlope = currentSlope; 73 | } 74 | } 75 | 76 | segments = lineSegments.toArray(new LineSegment[lineSegments.size()]); 77 | } 78 | 79 | public int numberOfSegments() { 80 | return segments.length; 81 | } 82 | 83 | public LineSegment[] segments() { 84 | return segments.clone(); 85 | } 86 | 87 | public static void main(String[] args) { 88 | 89 | // read the n points from a file 90 | In in = new In(args[0]); 91 | int n = in.readInt(); 92 | Point[] points = new Point[n]; 93 | for (int i = 0; i < n; i++) { 94 | int x = in.readInt(); 95 | int y = in.readInt(); 96 | points[i] = new Point(x, y); 97 | } 98 | 99 | // draw the points 100 | StdDraw.enableDoubleBuffering(); 101 | StdDraw.setXscale(0, 32768); 102 | StdDraw.setYscale(0, 32768); 103 | for (Point p : points) { 104 | p.draw(); 105 | } 106 | StdDraw.show(); 107 | 108 | // print and draw the line segments 109 | FastCollinearPoints collinear = new FastCollinearPoints(points); 110 | for (LineSegment segment : collinear.segments()) { 111 | StdOut.println(segment); 112 | segment.draw(); 113 | } 114 | StdDraw.show(); 115 | } 116 | } -------------------------------------------------------------------------------- /Pattern Recognition/LineSegment.java: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * Compilation: javac LineSegment.java 3 | * Execution: none 4 | * Dependencies: Point.java 5 | * 6 | * An immutable data type for Line segments in the plane. 7 | * For use on Coursera, Algorithms Part I programming assignment. 8 | * 9 | * DO NOT MODIFY THIS CODE. 10 | * 11 | *************************************************************************/ 12 | 13 | public class LineSegment { 14 | private final Point p; // one endpoint of this line segment 15 | private final Point q; // the other endpoint of this line segment 16 | 17 | /** 18 | * Initializes a new line segment. 19 | * 20 | * @param p one endpoint 21 | * @param q the other endpoint 22 | * @throws NullPointerException if either p or q 23 | * is null 24 | */ 25 | public LineSegment(Point p, Point q) { 26 | if (p == null || q == null) { 27 | throw new NullPointerException("argument is null"); 28 | } 29 | this.p = p; 30 | this.q = q; 31 | } 32 | 33 | 34 | /** 35 | * Draws this line segment to standard draw. 36 | */ 37 | public void draw() { 38 | p.drawTo(q); 39 | } 40 | 41 | /** 42 | * Returns a string representation of this line segment 43 | * This method is provide for debugging; 44 | * your program should not rely on the format of the string representation. 45 | * 46 | * @return a string representation of this line segment 47 | */ 48 | public String toString() { 49 | return p + " -> " + q; 50 | } 51 | 52 | /** 53 | * Throws an exception if called. The hashCode() method is not supported because 54 | * hashing has not yet been introduced in this course. Moreover, hashing does not 55 | * typically lead to good *worst-case* performance guarantees, as required on this 56 | * assignment. 57 | * 58 | * @throws UnsupportedOperationException if called 59 | */ 60 | public int hashCode() { 61 | throw new UnsupportedOperationException(); 62 | } 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /Pattern Recognition/Point.java: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Compilation: javac Point.java 3 | * Execution: java Point 4 | * Dependencies: none 5 | * 6 | * An immutable data type for points in the plane. 7 | * For use on Coursera, Algorithms Part I programming assignment. 8 | * 9 | ******************************************************************************/ 10 | 11 | import java.util.Comparator; 12 | import edu.princeton.cs.algs4.StdDraw; 13 | 14 | public class Point implements Comparable { 15 | 16 | private final int x; // x-coordinate of this point 17 | private final int y; // y-coordinate of this point 18 | 19 | /** 20 | * Initializes a new point. 21 | * 22 | * @param x the x-coordinate of the point 23 | * @param y the y-coordinate of the point 24 | */ 25 | public Point(int x, int y) { 26 | /* DO NOT MODIFY */ 27 | this.x = x; 28 | this.y = y; 29 | } 30 | 31 | /** 32 | * Draws this point to standard draw. 33 | */ 34 | public void draw() { 35 | /* DO NOT MODIFY */ 36 | StdDraw.point(x, y); 37 | } 38 | 39 | /** 40 | * Draws the line segment between this point and the specified point 41 | * to standard draw. 42 | * 43 | * @param that the other point 44 | */ 45 | public void drawTo(Point that) { 46 | /* DO NOT MODIFY */ 47 | StdDraw.line(this.x, this.y, that.x, that.y); 48 | } 49 | 50 | /** 51 | * Returns the slope between this point and the specified point. 52 | * Formally, if the two points are (x0, y0) and (x1, y1), then the slope 53 | * is (y1 - y0) / (x1 - x0). For completeness, the slope is defined to be 54 | * +0.0 if the line segment connecting the two points is horizontal; 55 | * Double.POSITIVE_INFINITY if the line segment is vertical; 56 | * and Double.NEGATIVE_INFINITY if (x0, y0) and (x1, y1) are equal. 57 | * 58 | * @param that the other point 59 | * @return the slope between this point and the specified point 60 | */ 61 | public double slopeTo(Point that) { 62 | if (this.compareTo(that) == 0) { 63 | return Double.NEGATIVE_INFINITY; 64 | } else if (this.y == that.y) { 65 | return 0.0; 66 | } else if (this.x == that.x) { 67 | return Double.POSITIVE_INFINITY; 68 | } else { 69 | return (that.y - this.y) / (double) (that.x - this.x); 70 | } 71 | } 72 | 73 | /** 74 | * Compares two points by y-coordinate, breaking ties by x-coordinate. 75 | * Formally, the invoking point (x0, y0) is less than the argument point 76 | * (x1, y1) if and only if either y0 < y1 or if y0 = y1 and x0 < x1. 77 | * 78 | * @param that the other point 79 | * @return the value 0 if this point is equal to the argument 80 | * point (x0 = x1 and y0 = y1); 81 | * a negative integer if this point is less than the argument 82 | * point; and a positive integer if this point is greater than the 83 | * argument point 84 | */ 85 | public int compareTo(Point that) { 86 | if (this.y == that.y) { 87 | return this.x - that.x; 88 | } else { 89 | return this.y - that.y; 90 | } 91 | } 92 | 93 | /** 94 | * Compares two points by the slope they make with this point. 95 | * The slope is defined as in the slopeTo() method. 96 | * 97 | * @return the Comparator that defines this ordering on points 98 | */ 99 | public Comparator slopeOrder() { 100 | return new Comparator() { 101 | @Override 102 | public int compare(Point point0, Point point1) { 103 | double slope0 = slopeTo(point0); 104 | double slope1 = slopeTo(point1); 105 | 106 | return Double.compare(slope0, slope1); 107 | } 108 | }; 109 | } 110 | 111 | 112 | /** 113 | * Returns a string representation of this point. 114 | * This method is provide for debugging; 115 | * your program should not rely on the format of the string representation. 116 | * 117 | * @return a string representation of this point 118 | */ 119 | public String toString() { 120 | /* DO NOT MODIFY */ 121 | return "(" + x + ", " + y + ")"; 122 | } 123 | 124 | /** 125 | * Unit tests the Point data type. 126 | */ 127 | public static void main(String[] args) { 128 | /* YOUR CODE HERE */ 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Pattern Recognition/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment: Collinear Points 2 | 3 | ### Write a program to recognize line patterns in a given set of points. 4 | 5 | Given a set of n distinct points in the plane, find every (maximal) line segment that connects a subset of 4 or more of the points. 6 | 7 | __Performance requirements.__ 8 | 9 | BruteCollinearPoints: The order of growth of the running time of your program should be n^4 in the worst case and it should use space proportional to n plus the number of line segments returned. 10 | 11 | FastCollinearPoints: The order of growth of the running time of your program should be n^2 log n in the worst case and it should use space proportional to n plus the number of line segments returned. -------------------------------------------------------------------------------- /Percolation/Percolation.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.WeightedQuickUnionUF; 2 | 3 | public class Percolation { 4 | private int topRoot = 0; 5 | private int bottomRoot = 0; 6 | private int openSites = 0; 7 | 8 | private int gridDimension; 9 | private WeightedQuickUnionUF unionFind; 10 | private WeightedQuickUnionUF fullSites; 11 | private boolean [][] sites; 12 | 13 | // create n-by-n grid, with all sites blocked 14 | public Percolation(int n) { 15 | if (n < 1) { 16 | throw new IllegalArgumentException(); 17 | } 18 | 19 | gridDimension = n; 20 | unionFind = new WeightedQuickUnionUF(n * n + 2); 21 | fullSites = new WeightedQuickUnionUF(n * n + 1); 22 | topRoot = n * n; 23 | bottomRoot = n * n + 1; 24 | sites = new boolean[n][n]; 25 | } 26 | 27 | // open site (row, col) if it is not open already 28 | public void open(int row, int col) { 29 | check(row, col); 30 | 31 | if (isOpen(row, col)) return; 32 | 33 | int index = index(row, col); 34 | 35 | // Top 36 | if (row == 1) { 37 | unionFind.union(index, topRoot); 38 | fullSites.union(index, topRoot); 39 | } else { 40 | int topRow = row - 1; 41 | unionIfOpen(topRow, col, index); 42 | } 43 | 44 | // Right 45 | if (col < gridDimension) { 46 | int rightCol = col + 1; 47 | unionIfOpen(row, rightCol, index); 48 | } 49 | 50 | // Bottom 51 | if (row == gridDimension) { 52 | unionFind.union(index, bottomRoot); 53 | } else { 54 | int bottomRow = row + 1; 55 | unionIfOpen(bottomRow, col, index); 56 | } 57 | 58 | // Left 59 | if (col > 1) { 60 | int leftCol = col - 1; 61 | unionIfOpen(row, leftCol, index); 62 | } 63 | 64 | sites[row - 1][col - 1] = true; 65 | openSites++; 66 | } 67 | 68 | // is site (row, col) open? 69 | public boolean isOpen(int row, int col) { 70 | check(row, col); 71 | 72 | return sites[row - 1][col - 1] == true; 73 | } 74 | 75 | // is site (row, col) full? 76 | public boolean isFull(int row, int col) { 77 | check(row, col); 78 | 79 | int index = index(row, col); 80 | return fullSites.connected(index, topRoot); 81 | } 82 | 83 | // number of open sites 84 | public int numberOfOpenSites() { 85 | return openSites; 86 | } 87 | 88 | // does the system percolate? 89 | public boolean percolates() { 90 | return unionFind.connected(topRoot, bottomRoot); 91 | } 92 | 93 | // Helpers 94 | private int index(int row, int col) { 95 | return gridDimension * (row - 1) + (col - 1); 96 | } 97 | 98 | private void unionIfOpen(int row, int col, int indexToUnion) { 99 | if (isOpen(row, col)) { 100 | int index = index(row, col); 101 | unionFind.union(index, indexToUnion); 102 | fullSites.union(index, indexToUnion); 103 | } 104 | } 105 | 106 | private void check(int row, int col) { 107 | if (row < 1 || row > gridDimension || col < 1 || col > gridDimension) { 108 | throw new IllegalArgumentException(); 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /Percolation/PercolationStats.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.StdRandom; 2 | import edu.princeton.cs.algs4.StdStats; 3 | import edu.princeton.cs.algs4.StdOut; 4 | 5 | public class PercolationStats { 6 | private static final double CONFIDENCE_95 = 1.96; 7 | private double[] thresholds; 8 | private double mean = -1; 9 | private double stddev = -1; 10 | 11 | // perform trials independent experiments on an n-by-n grid 12 | public PercolationStats(int n, int trials) { 13 | if (n < 1 || trials < 1) { 14 | throw new IllegalArgumentException(); 15 | } 16 | 17 | thresholds = new double[trials]; 18 | 19 | for (int i = 0; i < trials; i++) { 20 | Percolation percolation = new Percolation(n); 21 | 22 | while (!percolation.percolates()) { 23 | int row = StdRandom.uniform(n) + 1; 24 | int col = StdRandom.uniform(n) + 1; 25 | 26 | percolation.open(row, col); 27 | } 28 | 29 | thresholds[i] = percolation.numberOfOpenSites() / (double) (n * n); 30 | } 31 | } 32 | 33 | // sample mean of percolation threshold 34 | public double mean() { 35 | if (mean == -1) { 36 | mean = StdStats.mean(thresholds); 37 | } 38 | 39 | return mean; 40 | } 41 | 42 | // sample standard deviation of percolation threshold 43 | public double stddev() { 44 | if (stddev == -1) { 45 | stddev = StdStats.stddev(thresholds); 46 | } 47 | 48 | return stddev; 49 | } 50 | 51 | // low endpoint of 95% confidence interval 52 | public double confidenceLo() { 53 | return mean() - (CONFIDENCE_95 * stddev()) / Math.sqrt(thresholds.length); 54 | } 55 | 56 | // high endpoint of 95% confidence interval 57 | public double confidenceHi() { 58 | return mean() + (CONFIDENCE_95 * stddev()) / Math.sqrt(thresholds.length); 59 | } 60 | 61 | // test client (described below) 62 | public static void main(String[] args) { 63 | 64 | if (args.length < 2) { 65 | throw new IllegalArgumentException(); 66 | } 67 | 68 | int gridSize = 0; 69 | int trials = 0; 70 | 71 | try { 72 | gridSize = Integer.parseInt(args[0]); 73 | trials = Integer.parseInt(args[1]); 74 | } finally {} 75 | 76 | PercolationStats stats = new PercolationStats(gridSize, trials); 77 | 78 | StdOut.println("mean = " + stats.mean()); 79 | StdOut.println("stddev = " + stats.stddev()); 80 | StdOut.println("95% confidence interval = [" + stats.confidenceLo() +", " + stats.confidenceHi() + "]"); 81 | } 82 | } -------------------------------------------------------------------------------- /Percolation/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment 1: Percolation 2 | 3 | ### Write a program to estimate the value of the percolation threshold via Monte Carlo simulation. 4 | 5 | Monte Carlo simulation. To estimate the percolation threshold, consider the following computational experiment: 6 | 7 | * Initialize all sites to be blocked. 8 | * Repeat the following until the system percolates: 9 | * Choose a site uniformly at random among all blocked sites. 10 | * Open the site. 11 | * The fraction of sites that are opened when the system percolates provides an estimate of the percolation threshold. 12 | 13 | __Performance requirements.__ 14 | The constructor should take time proportional to n2; all methods should take constant time plus a constant number of calls to the union–find methods union(), find(), connected(), and count(). -------------------------------------------------------------------------------- /Queues/Deque.java: -------------------------------------------------------------------------------- 1 | import java.util.Iterator; 2 | import java.util.NoSuchElementException; 3 | 4 | public class Deque implements Iterable { 5 | 6 | private Node head; 7 | private Node tail; 8 | private int size = 0; 9 | 10 | private class Node { 11 | Item item; 12 | Node prev; 13 | Node next; 14 | } 15 | 16 | public Deque() { } 17 | 18 | public boolean isEmpty() { 19 | return size == 0; 20 | } 21 | 22 | public int size() { 23 | return size; 24 | } 25 | 26 | public void addFirst(Item item) { 27 | if (item == null) { throw new IllegalArgumentException(); } 28 | 29 | Node node = new Node(); 30 | node.item = item; 31 | 32 | if (head == null) { 33 | head = node; 34 | tail = node; 35 | } else { 36 | node.prev = head; 37 | head.next = node; 38 | head = node; 39 | } 40 | 41 | size++; 42 | } 43 | 44 | public void addLast(Item item) { 45 | if (item == null) { throw new IllegalArgumentException(); } 46 | 47 | Node node = new Node(); 48 | node.item = item; 49 | 50 | if (tail == null) { 51 | tail = node; 52 | head = node; 53 | } else { 54 | node.next = tail; 55 | tail.prev = node; 56 | tail = node; 57 | } 58 | 59 | size++; 60 | } 61 | 62 | public Item removeFirst() { 63 | if (size == 0) { throw new NoSuchElementException(); } 64 | 65 | Item item = head.item; 66 | 67 | if (size == 1) { 68 | head = null; 69 | tail = null; 70 | } else { 71 | head = head.prev; 72 | head.next = null; 73 | 74 | if (size == 2) { 75 | tail = head; 76 | } 77 | } 78 | 79 | size--; 80 | return item; 81 | } 82 | 83 | public Item removeLast() { 84 | if (size == 0) { throw new NoSuchElementException(); } 85 | 86 | Item item = tail.item; 87 | 88 | if (size == 1) { 89 | head = null; 90 | tail = null; 91 | } else { 92 | tail = tail.next; 93 | tail.prev = null; 94 | 95 | if (size == 2) { 96 | head = tail; 97 | } 98 | } 99 | 100 | size--; 101 | return item; 102 | } 103 | 104 | public Iterator iterator() { return new DequeIterator(); } 105 | 106 | private class DequeIterator implements Iterator { 107 | private Node current = head; 108 | 109 | public boolean hasNext() { return current != null; } 110 | public void remove() { throw new UnsupportedOperationException(); } 111 | public Item next() { 112 | if (!hasNext()) { throw new NoSuchElementException(); } 113 | 114 | Item item = current.item; 115 | current = current.prev; 116 | return item; 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /Queues/Permutation.java: -------------------------------------------------------------------------------- 1 | import java.util.Iterator; 2 | import edu.princeton.cs.algs4.StdOut; 3 | import edu.princeton.cs.algs4.StdIn; 4 | 5 | public class Permutation { 6 | public static void main(String[] args) { 7 | int count = Integer.parseInt(args[0]); 8 | RandomizedQueue queue = new RandomizedQueue(); 9 | 10 | while (true) { 11 | String line = null; 12 | try { 13 | line = StdIn.readString(); 14 | } finally { if (line == null) break; } 15 | 16 | queue.enqueue(line); 17 | } 18 | 19 | Iterator iterator = queue.iterator(); 20 | 21 | while (count-- > 0) { 22 | StdOut.println(iterator.next()); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Queues/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment 2: Deques and Randomized Queues 2 | 3 | ### Write a generic data type for a deque and a randomized queue. The goal of this assignment is to implement elementary data structures using arrays and linked lists, and to introduce you to generics and iterators. 4 | 5 | ### Dequeue 6 | A double-ended queue or deque (pronounced “deck”) is a generalization of a stack and a queue that supports adding and removing items from either the front or the back of the data structure. 7 | 8 | __Performance requirements.__ Your deque implementation must support each deque operation (including construction) in constant worst-case time. A deque containing n items must use at most 48n + 192 bytes of memory and use space proportional to the number of items currently in the deque. Additionally, your iterator implementation must support each operation (including construction) in constant worst-case time. 9 | 10 | 11 | ### Randomized queue 12 | A randomized queue is similar to a stack or queue, except that the item removed is chosen uniformly at random from items in the data structure. 13 | 14 | __Performance requirements.__ Your randomized queue implementation must support each randomized queue operation (besides creating an iterator) in constant amortized time. That is, any sequence of m randomized queue operations (starting from an empty queue) must take at most cm steps in the worst case, for some constant c. A randomized queue containing n items must use at most 48n + 192 bytes of memory. Additionally, your iterator implementation must support operations next() and hasNext() in constant worst-case time; and construction in linear time; you may (and will need to) use a linear amount of extra memory per iterator. -------------------------------------------------------------------------------- /Queues/RandomizedQueue.java: -------------------------------------------------------------------------------- 1 | import java.util.Iterator; 2 | import java.util.NoSuchElementException; 3 | import edu.princeton.cs.algs4.StdRandom; 4 | 5 | public class RandomizedQueue implements Iterable { 6 | private Item[] storage; 7 | private int size = 0; 8 | 9 | public RandomizedQueue() { 10 | storage = (Item[]) new Object[1]; 11 | } 12 | 13 | public boolean isEmpty() { 14 | return size == 0; 15 | } 16 | 17 | public int size() { 18 | return size; 19 | } 20 | 21 | public void enqueue(Item item) { 22 | if (item == null) { throw new IllegalArgumentException(); } 23 | 24 | storage[size] = item; 25 | size++; 26 | resizeIfNeed(); 27 | } 28 | 29 | public Item dequeue() { 30 | if (size == 0) { throw new NoSuchElementException(); } 31 | 32 | int index = StdRandom.uniform(size); 33 | Item item = storage[index]; 34 | storage[index] = storage[--size]; 35 | 36 | resizeIfNeed(); 37 | return item; 38 | } 39 | 40 | public Item sample() { 41 | if (size == 0) { throw new NoSuchElementException(); } 42 | 43 | return storage[StdRandom.uniform(size)]; 44 | } 45 | 46 | public Iterator iterator() { return new RandomizedQueueIterator(); } 47 | 48 | private class RandomizedQueueIterator implements Iterator { 49 | private final int[] indices = new int[size]; 50 | private int currentIndex = 0; 51 | 52 | public RandomizedQueueIterator() { 53 | for (int i = 0; i < size; i++) { 54 | indices[i] = i; 55 | } 56 | 57 | StdRandom.shuffle(indices); 58 | } 59 | 60 | public boolean hasNext() { return currentIndex < indices.length; } 61 | public void remove() { throw new UnsupportedOperationException(); } 62 | public Item next() { 63 | if (!hasNext()) { throw new NoSuchElementException(); } 64 | return storage[indices[currentIndex++]]; 65 | } 66 | } 67 | 68 | private void resizeIfNeed() { 69 | if (size == storage.length) { 70 | resize(storage.length * 2); 71 | } else if (size <= storage.length / 4) { 72 | resize(storage.length / 2); 73 | } 74 | } 75 | 76 | private void resize(int newSize) { 77 | Item[] newStorage = (Item[]) new Object[newSize]; 78 | for (int i = 0; i < size; i++) { 79 | newStorage[i] = storage[i]; 80 | } 81 | storage = newStorage; 82 | } 83 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Solutions for Coursera Algorithms course, by Princeton University 2 | 3 | ### Part 1 4 | * [Percolation (Week 1, 100/100)](/Percolation/) 5 | * [Queues (Week 2, 100/100)](/Queues/) 6 | * [Pattern Recognition (Week 3, 100/100)](/Pattern%20Recognition/) 7 | * [8 Puzzle (Week 4, 100/100)](/8%20Puzzle/) 8 | * [Kd-Tree (Week 5, 100/100)](/Kd-Tree/) 9 | 10 | ### Part 2 11 | * [WordNet (Week 1, 100/100)](/WordNet/) 12 | * [Seam Carving (Week 2, 100/100)](/Seam%20Carving/) 13 | * [Baseball Elimination (Week 3, 100/100)](/Baseball%20Elimination/) 14 | * [Boggle (Week 4, 100/100)](/Boggle/) 15 | * [Burrows–Wheeler (Week 5, 100/100)](/Burrows–Wheeler/) -------------------------------------------------------------------------------- /Seam Carving/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment 2: Seam Carving 2 | 3 | [Assignment Specification](http://coursera.cs.princeton.edu/algs4/assignments/seam.html) 4 | 5 | ### Seam-carving is a content-aware image resizing technique where the image is reduced in size by one pixel of height (or width) at a time. A vertical seam in an image is a path of pixels connected from the top to the bottom with one pixel in each row. 6 | 7 | __Performance requirements.__ The width(), height(), and energy() methods should take constant time in the worst case. All other methods should run in time at most proportional to width × height in the worst case. For faster performance, do not construct explicit DirectedEdge and EdgeWeightedDigraph objects. -------------------------------------------------------------------------------- /Seam Carving/SeamCarver.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.Picture; 2 | import java.awt.Color; 3 | 4 | public class SeamCarver { 5 | private static final boolean HORIZONTAL = true; 6 | private static final boolean VERTICAL = false; 7 | 8 | private Picture picture; 9 | private double[] distTo; 10 | private int[][] edgeTo; 11 | 12 | // create a seam carver object based on the given picture 13 | public SeamCarver(Picture picture) { 14 | if (picture == null) { 15 | throw new IllegalArgumentException(); 16 | } 17 | 18 | this.picture = new Picture(picture); 19 | } 20 | 21 | // current picture 22 | public Picture picture() { 23 | return new Picture(this.picture); 24 | } 25 | 26 | // width of current picture 27 | public int width() { 28 | return this.picture.width(); 29 | } 30 | 31 | // height of current picture 32 | public int height() { 33 | return this.picture.height(); 34 | } 35 | 36 | // energy of pixel at column x and row y 37 | public double energy(int x, int y) { 38 | if (x < 0 || y < 0 || x > width() - 1 || y > height() - 1) { 39 | throw new IllegalArgumentException(); 40 | } 41 | 42 | if (x == 0 || y == 0 || x == width() - 1 || y == height() - 1) { 43 | return 1000; 44 | } 45 | 46 | Color top = this.picture.get(x, y + 1); 47 | Color bottom = this.picture.get(x, y - 1); 48 | Color left = this.picture.get(x - 1, y); 49 | Color right = this.picture.get(x + 1, y); 50 | 51 | return Math.sqrt(squareGradient(top, bottom) + squareGradient(left, right)); 52 | } 53 | 54 | private double squareGradient(Color first, Color second) { 55 | return Math.pow(first.getRed() - second.getRed(), 2) + 56 | Math.pow(first.getGreen() - second.getGreen(), 2) + 57 | Math.pow(first.getBlue() - second.getBlue(), 2); 58 | } 59 | 60 | // sequence of indices for horizontal seam 61 | public int[] findHorizontalSeam() { 62 | return seam(HORIZONTAL); 63 | } 64 | 65 | // sequence of indices for vertical seam 66 | public int[] findVerticalSeam() { 67 | return seam(VERTICAL); 68 | } 69 | 70 | private int[] seam(boolean direction) { 71 | this.distTo = (direction == VERTICAL) ? new double[this.width()] : new double[this.height()]; 72 | this.edgeTo = new int[this.width()][this.height()]; 73 | 74 | for (int i = 0; i < this.distTo.length; i++) { 75 | this.distTo[i] = 1000; 76 | } 77 | 78 | int maxI = (direction == VERTICAL) ? this.height() : this.width(); 79 | int maxJ = (direction == VERTICAL) ? this.width() : this.height(); 80 | 81 | for (int i = 1; i < maxI; i++) { 82 | double[] lastDistTo = this.distTo.clone(); 83 | for (int k = 0; k < this.distTo.length; k++) { 84 | this.distTo[k] = Double.POSITIVE_INFINITY; 85 | } 86 | 87 | for (int j = 1; j < maxJ; j++) { 88 | int x = (direction == VERTICAL) ? j : i; 89 | int y = (direction == VERTICAL) ? i : j; 90 | 91 | double energy = energy(x, y); 92 | 93 | relax(j - 1, x, y, energy, lastDistTo, direction); 94 | relax(j , x, y, energy, lastDistTo, direction); 95 | relax(j + 1, x, y, energy, lastDistTo, direction); 96 | } 97 | } 98 | 99 | double minWeight = Double.POSITIVE_INFINITY; 100 | int min = 0; 101 | 102 | for (int i = 0; i < this.distTo.length; i++) { 103 | double weight = this.distTo[i]; 104 | if (weight < minWeight) { 105 | min = i; 106 | minWeight = weight; 107 | } 108 | } 109 | 110 | int[] seam = (direction == VERTICAL) ? new int[this.height()] : new int[this.width()]; 111 | 112 | if (direction == VERTICAL) { 113 | for (int y = this.height() - 1; y >= 0; y--) { 114 | seam[y] = min; 115 | min = edgeTo[min][y]; 116 | } 117 | } else { 118 | for (int x = this.width() - 1; x >= 0; x--) { 119 | seam[x] = min; 120 | min = edgeTo[x][min]; 121 | } 122 | } 123 | 124 | return seam; 125 | } 126 | private void relax(int prev, int x, int y, double energy, double[] lastDistTo, boolean direction) { 127 | if (prev < 0 || prev >= lastDistTo.length) { 128 | return; 129 | } 130 | 131 | double weight = lastDistTo[prev]; 132 | 133 | int index = (direction == VERTICAL) ? x : y; 134 | if (this.distTo[index] > weight + energy) { 135 | this.distTo[index] = weight + energy; 136 | this.edgeTo[x][y] = prev; 137 | } 138 | } 139 | 140 | // remove horizontal seam from current picture 141 | public void removeHorizontalSeam(int[] seam) { 142 | if (seam == null || this.height() <= 1 || seam.length != this.width()) { 143 | throw new IllegalArgumentException(); 144 | } 145 | 146 | Picture newPicture = new Picture(this.width(), this.height() - 1); 147 | 148 | int prevSeam = seam[0]; 149 | 150 | for (int x = 0; x < this.width(); x++) { 151 | if (Math.abs(seam[x] - prevSeam) > 1 || seam[x] < 0 || seam[x] >= this.height()) { 152 | throw new IllegalArgumentException(); 153 | } 154 | prevSeam = seam[x]; 155 | 156 | for (int y = 0; y < this.height(); y++) { 157 | if (seam[x] == y) continue; 158 | 159 | Color color = this.picture.get(x, y); 160 | newPicture.set(x, seam[x] > y ? y : y - 1, color); 161 | } 162 | } 163 | 164 | this.picture = newPicture; 165 | } 166 | 167 | // remove vertical seam from current picture 168 | public void removeVerticalSeam(int[] seam) { 169 | if (seam == null || this.width() <= 1 || seam.length != this.height()) { 170 | throw new IllegalArgumentException(); 171 | } 172 | 173 | Picture newPicture = new Picture(this.width() - 1, this.height()); 174 | 175 | int prevSeam = seam[0]; 176 | 177 | for (int y = 0; y < this.height(); y++) { 178 | if (Math.abs(seam[y] - prevSeam) > 1 || seam[y] < 0 || seam[y] >= this.width()) { 179 | throw new IllegalArgumentException(); 180 | } 181 | prevSeam = seam[y]; 182 | 183 | for (int x = 0; x < this.width(); x++) { 184 | if (seam[y] == x) continue; 185 | 186 | Color color = this.picture.get(x, y); 187 | newPicture.set(seam[y] > x ? x : x - 1, y, color); 188 | } 189 | } 190 | 191 | this.picture = newPicture; 192 | } 193 | } -------------------------------------------------------------------------------- /WordNet/Outcast.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.In; 2 | import edu.princeton.cs.algs4.StdOut; 3 | 4 | public class Outcast { 5 | private final WordNet wordNet; 6 | 7 | // constructor takes a WordNet object 8 | public Outcast(WordNet wordnet) { 9 | this.wordNet = wordnet; 10 | } 11 | 12 | // given an array of WordNet nouns, return an outcast 13 | public String outcast(String[] nouns) { 14 | int outcaseDistance = 0; 15 | String outcast = nouns[0]; 16 | 17 | for (String noun : nouns) { 18 | int distance = distance(noun, nouns); 19 | 20 | if (distance > outcaseDistance) { 21 | outcaseDistance = distance; 22 | outcast = noun; 23 | } 24 | } 25 | 26 | return outcast; 27 | } 28 | 29 | private int distance(String noun, String[] nouns) { 30 | int distance = 0; 31 | 32 | for (int i = 0; i < nouns.length; i++) { 33 | distance += this.wordNet.distance(noun, nouns[i]); 34 | } 35 | 36 | return distance; 37 | } 38 | 39 | // see test client below 40 | public static void main(String[] args) { 41 | WordNet wordnet = new WordNet(args[0], args[1]); 42 | Outcast outcast = new Outcast(wordnet); 43 | for (int t = 2; t < args.length; t++) { 44 | In in = new In(args[t]); 45 | String[] nouns = in.readAllStrings(); 46 | StdOut.println(args[t] + ": " + outcast.outcast(nouns)); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /WordNet/README.md: -------------------------------------------------------------------------------- 1 | ## Programming Assignment 1: WordNet 2 | 3 | [Assignment Specification](http://coursera.cs.princeton.edu/algs4/assignments/wordnet.html) 4 | 5 | ### WordNet is a semantic lexicon for the English language that is used extensively by computational linguists and cognitive scientists; for example, it was a key component in IBM's Watson. WordNet groups words into sets of synonyms called synsets and describes semantic relationships between them. One such relationship is the is-a relationship, which connects a hyponym (more specific synset) to a hypernym (more general synset). For example, animal is a hypernym of both bird and fish; bird is a hypernym of eagle, pigeon, and seagull. 6 | 7 | __The WordNet digraph.__ Your first task is to build the wordnet digraph: each vertex v is an integer that represents a synset, and each directed edge v→w represents that w is a hypernym of v. 8 | 9 | __Shortest ancestral path.__ An ancestral path between two vertices v and w in a digraph is a directed path from v to a common ancestor x, together with a directed path from w to the same ancestor x. A shortest ancestral path is an ancestral path of minimum total length. 10 | 11 | __Outcast detection.__ Given a list of wordnet nouns A1, A2, ..., An, which noun is the least related to the others? -------------------------------------------------------------------------------- /WordNet/SAP.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.BreadthFirstDirectedPaths; 2 | import edu.princeton.cs.algs4.Digraph; 3 | import edu.princeton.cs.algs4.In; 4 | import edu.princeton.cs.algs4.StdIn; 5 | import edu.princeton.cs.algs4.StdOut; 6 | 7 | public class SAP { 8 | private final Digraph digraph; 9 | 10 | private class SAPResult { 11 | int ancestor; 12 | int length; 13 | 14 | public SAPResult(int ancestor, int length) { 15 | this.ancestor = ancestor; 16 | this.length = length; 17 | } 18 | } 19 | 20 | // constructor takes a digraph (not necessarily a DAG) 21 | public SAP(Digraph G) { 22 | if (G == null) { 23 | throw new IllegalArgumentException(); 24 | } 25 | 26 | digraph = new Digraph(G); 27 | } 28 | 29 | // length of shortest ancestral path between v and w; -1 if no such path 30 | public int length(int v, int w) { 31 | checkArguments(v, w); 32 | 33 | return findSAP(v, w).length; 34 | } 35 | 36 | // a common ancestor of v and w that participates in a shortest ancestral path; -1 if no such path 37 | public int ancestor(int v, int w) { 38 | checkArguments(v, w); 39 | 40 | return findSAP(v, w).ancestor; 41 | } 42 | 43 | // length of shortest ancestral path between any vertex in v and any vertex in w; -1 if no such path 44 | public int length(Iterable v, Iterable w) { 45 | checkArguments(v, w); 46 | 47 | return findSAP(v, w).length; 48 | } 49 | 50 | // a common ancestor that participates in shortest ancestral path; -1 if no such path 51 | public int ancestor(Iterable v, Iterable w) { 52 | checkArguments(v, w); 53 | 54 | return findSAP(v, w).ancestor; 55 | } 56 | 57 | // do unit testing of this class 58 | public static void main(String[] args) { 59 | In in = new In(args[0]); 60 | Digraph G = new Digraph(in); 61 | SAP sap = new SAP(G); 62 | while (!StdIn.isEmpty()) { 63 | int v = StdIn.readInt(); 64 | int w = StdIn.readInt(); 65 | int length = sap.length(v, w); 66 | int ancestor = sap.ancestor(v, w); 67 | StdOut.printf("length = %d, ancestor = %d\n", length, ancestor); 68 | } 69 | } 70 | 71 | private void checkArguments(int v, int w) { 72 | if (v < 0 || w < 0 || v > digraph.V() - 1 || w > digraph.V() - 1) { 73 | throw new IllegalArgumentException(); 74 | } 75 | } 76 | 77 | private void checkArguments(Iterable v, Iterable w) { 78 | if (v == null || w == null) { 79 | throw new IllegalArgumentException(); 80 | } 81 | 82 | for (int value : v) { 83 | if (value > digraph.V() - 1) { 84 | throw new IllegalArgumentException(); 85 | } 86 | } 87 | 88 | for (int value : w) { 89 | if (value > digraph.V() - 1) { 90 | throw new IllegalArgumentException(); 91 | } 92 | } 93 | } 94 | 95 | private SAPResult findSAP(int v, int w) { 96 | BreadthFirstDirectedPaths vBFS = new BreadthFirstDirectedPaths(digraph, v); 97 | BreadthFirstDirectedPaths wBFS = new BreadthFirstDirectedPaths(digraph, w); 98 | 99 | return findSAP(vBFS, wBFS); 100 | } 101 | 102 | private SAPResult findSAP(Iterable v, Iterable w) { 103 | BreadthFirstDirectedPaths vBFS = new BreadthFirstDirectedPaths(digraph, v); 104 | BreadthFirstDirectedPaths wBFS = new BreadthFirstDirectedPaths(digraph, w); 105 | 106 | return findSAP(vBFS, wBFS); 107 | } 108 | 109 | private SAPResult findSAP(BreadthFirstDirectedPaths vBFS, BreadthFirstDirectedPaths wBFS) { 110 | SAPResult result = new SAPResult(-1, -1); 111 | 112 | for (int i = 0; i < digraph.V(); i++) { 113 | if (vBFS.hasPathTo(i) && wBFS.hasPathTo(i)) { 114 | int length = vBFS.distTo(i) + wBFS.distTo(i); 115 | if (result.length == -1 || result.length > length) { 116 | result.length = length; 117 | result.ancestor = i; 118 | } 119 | } 120 | } 121 | 122 | return result; 123 | } 124 | } -------------------------------------------------------------------------------- /WordNet/WordNet.java: -------------------------------------------------------------------------------- 1 | import edu.princeton.cs.algs4.In; 2 | import edu.princeton.cs.algs4.Digraph; 3 | import edu.princeton.cs.algs4.DirectedCycle; 4 | import edu.princeton.cs.algs4.SET; 5 | import java.util.HashMap; 6 | 7 | public class WordNet { 8 | private final HashMap> nouns; 9 | private final HashMap> synsets; 10 | private final Digraph dag; 11 | private final SAP sap; 12 | 13 | // constructor takes the name of the two input files 14 | public WordNet(String synsets, String hypernyms) { 15 | checkArguments(synsets, hypernyms); 16 | 17 | this.nouns = new HashMap>(); 18 | this.synsets = new HashMap>(); 19 | parseSynsets(readAllLines(synsets)); 20 | 21 | this.dag = new Digraph(this.synsets.keySet().size()); 22 | parseHypernyms(readAllLines(hypernyms)); 23 | 24 | this.sap = new SAP(this.dag); 25 | 26 | checkRoot(); 27 | checkCycle(); 28 | } 29 | 30 | private void checkRoot() { 31 | int roots = 0; 32 | for (int i = 0; i < this.dag.V(); i++) { 33 | if (this.dag.outdegree(i) == 0) { 34 | roots++; 35 | } 36 | } 37 | 38 | if (roots != 1) { 39 | throw new IllegalArgumentException(); 40 | } 41 | } 42 | 43 | private void checkCycle() { 44 | DirectedCycle directedCycle = new DirectedCycle(this.dag); 45 | 46 | if (directedCycle.hasCycle()) { 47 | throw new IllegalArgumentException(); 48 | } 49 | } 50 | 51 | private void parseSynsets(String[] lines) { 52 | for (String line : lines) { 53 | String[] fields = line.split(","); 54 | int id = Integer.parseInt(fields[0]); 55 | SET synset = new SET(); 56 | 57 | for (String noun : fields[1].split(" ")) { 58 | synset.add(noun); 59 | 60 | SET knownIds = this.nouns.get(noun); 61 | if (knownIds == null) { 62 | knownIds = new SET(); 63 | this.nouns.put(noun, knownIds); 64 | } 65 | knownIds.add(id); 66 | } 67 | 68 | this.synsets.put(id, synset); 69 | } 70 | } 71 | 72 | private void parseHypernyms(String[] lines) { 73 | for (String line : lines) { 74 | String[] fields = line.split(","); 75 | int synsetId = Integer.parseInt(fields[0]); 76 | 77 | for (int i = 1; i < fields.length; i++) { 78 | int hypernymId = Integer.parseInt(fields[i]); 79 | dag.addEdge(synsetId, hypernymId); 80 | } 81 | } 82 | } 83 | 84 | private String[] readAllLines(String filename) { 85 | In in = new In(filename); 86 | String[] lines = in.readAllLines(); 87 | in.close(); 88 | return lines; 89 | } 90 | 91 | // returns all WordNet nouns 92 | public Iterable nouns() { 93 | return this.nouns.keySet(); 94 | } 95 | 96 | // is the word a WordNet noun? 97 | public boolean isNoun(String word) { 98 | checkArgument(word); 99 | 100 | return this.nouns.get(word) != null; 101 | } 102 | 103 | // distance between nounA and nounB (defined below) 104 | public int distance(String nounA, String nounB) { 105 | checkArguments(nounA, nounB); 106 | 107 | SET aId = this.nouns.get(nounA); 108 | SET bId = this.nouns.get(nounB); 109 | 110 | checkArguments(aId, bId); 111 | 112 | return this.sap.length(aId, bId); 113 | } 114 | 115 | // a synset (second field of synsets.txt) that is the common ancestor of nounA and nounB 116 | // in a shortest ancestral path (defined below) 117 | public String sap(String nounA, String nounB) { 118 | checkArguments(nounA, nounB); 119 | 120 | SET aId = this.nouns.get(nounA); 121 | SET bId = this.nouns.get(nounB); 122 | 123 | checkArguments(aId, bId); 124 | 125 | int ancestor = this.sap.ancestor(aId, bId); 126 | return setToString(this.synsets.get(ancestor)); 127 | } 128 | 129 | private String setToString(SET set) { 130 | String result = ""; 131 | for (String element : set) { 132 | result += " " + element; 133 | } 134 | 135 | return result; 136 | } 137 | 138 | private void checkArgument(String argument) { 139 | if (argument == null) { 140 | throw new IllegalArgumentException(); 141 | } 142 | } 143 | 144 | private void checkArguments(String argument1, String argument2) { 145 | if (argument1 == null || argument2 == null) { 146 | throw new IllegalArgumentException(); 147 | } 148 | } 149 | 150 | private void checkArguments(SET argument1, SET argument2) { 151 | if (argument1 == null || argument2 == null) { 152 | throw new IllegalArgumentException(); 153 | } 154 | } 155 | } --------------------------------------------------------------------------------