I was wondering if there is a way or a library I can use to do the following:
I have an arraylist of objects where each obj has a name.
The list needs to always be unique with a maximum of 5 elements like [E1,E2,E3]
If for example the list has initial form [E3,E5] and I add an object, its name should be E1 and the list will be [E1,E3,E5] or [E3,E5,E1] it doesn't matter, as long as the name is unique and the item is added to the list starting from 1 to 5.
If add another item, it should be [E3,E5,E1,E2], always a unique name and between 1 and 5
These are my failed attempts,
StartNode node = new StartNode();
node.setName("E1");
for (int i = 0; i < circuit.getNbStartNodes(); i++) {
for (int j = 1; j <= circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (("E"+j).equalsIgnoreCase(test) && ("E"+j).equalsIgnoreCase(node.getName()) ) {
break;
}
else
node.setName("E" + j);
}
}
/*while (t <= circuit.getNbStartNodes()) {
for (int j = 0; j < circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (("E" + t).equalsIgnoreCase(test) || ("E" + t).equalsIgnoreCase(node.getName()))
break;
else {
node.setName("E" + t);
}
}
t++;
}
*/
/* for (int i = 1; i <= circuit.getNbStartNodes(); i++) {
for (int j = 0; j < circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (!("E" + i).equalsIgnoreCase(test)) {
node.setName("E" + i);
t=0;
break;
}
}
if (t==0)
break;
else
continue;
*/
//String test = ((StartNode) circuit.getStartNode(i)).getName();
//for (int j = 1; j <= circuit.getNbStartNodes(); j++) {
// if (!("E" + j).equalsIgnoreCase(test))
// node.setName("E" + j);
//}
What did I do wrong in my code?
Create a small boolean array to track which names are already used and populate it with accordingly
Find the first unused element and use it as id.
boolean[] used = new boolean[circuit.getNbStartNodes()];
for (int i = 0; i < used.length; i++) {
int index = Integer.parseInt(((StartNode) circuit.getStartNode(j)).getName().substring(1)) - 1; // should be in range 0..4
used[index] = true;
}
String name = "E";
for (int i = 0; i < used.length; i++) {
if (!used[i]) {
name += String.valueOf(i + 1); // starting from 1
break;
}
}
System.out.println("free name: " + name);
StartNode node = new StartNode();
node.setName(name);
// add new node to circuit, etc.
With small values, Alex' solution works fine.
However, if you ever come across a use case where the number of elements become potentially large, then you could use a TreeSet to keep track of the unused numbers. Further, the nextCeilValue is the next number to pick when there are no removed numbers.
In the below code, I have created a UniqueNumber class, which is able to get the next number, or remove a given number. Note that this code provides integers starting from 0. Of course, you could easily convert this to your E-numbers using the function i -> "E" + (i + 1).
public class UniqueNumber {
private int nextCeilValue;
private final TreeSet<Integer> removedNumbers = new TreeSet<>(Integer::compare);
public int get() {
if (removedNumbers.isEmpty()) {
return nextCeilValue++;
}
else {
int number = removedNumbers.first();
removedNumbers.remove(number);
return number;
}
}
public boolean remove(int number) {
if (number < 0 || number > nextCeilValue) {
return false;
}
if (number == nextCeilValue) {
nextCeilValue--;
}
else {
removedNumbers.add(number);
}
return true;
}
public int size() {
return nextCeilValue - removedNumbers.size();
}
}
In order to test this, we first need to simulate your initial situation. In our integer-starting-from-zero-world, we need the numbers 2 and 4 (representing E3 and E5). In below code, we need to call get five times, and then remove element 0, 1 and 3. Of course, we could have created a UniqueNumber(int... initialValues) constructor which does this under the hood.
UniqueNumber un = new UniqueNumber();
for (int i = 0; i < 5; i++) {
un.get();
}
un.remove(0); // Remove E1
un.remove(1); // Remove E2
un.remove(3); // Remove E4
In order to get the next value, simply use this:
StartNode node = new StartNode();
node.setName("E" + (un.get() + 1));
Related
In the code below i try to read a file with the size of a 2d array and the numbers for each cell. Then the program must find a number that can be added in the cell with a zero value in magic array. All this in order to create magic squares based on the initialized magic array with the elements of the external file. The problem is that i always get the message "magic squares cannot be created" even when the if statement in next_successor method get true from all the arguments? where is the problem? i got really stuck any help will be appreciated!
so i think the main problem is with the methods:
next_successor
check_row
check_column
check_diagonals
The rules that i have to follow in order to create the methods are:
In order for current_number to be inserted into magic[row,column], the following checks (by check_row(), check_column() and check_diagonals()) should be made:
For each of the row, column, and possibly main diagonals (in the case of row=column or row=N-column-1) to which position magic[row,column] belongs, and for each current_number that does not has yet been inserted into the magic square (according to the value used[current_number-1]), we perform the following checks to decide whether current_number can be inserted into magic[row,column]:
Suppose (in the row or column or main diagonal where the position magic[row,column]) is located after the number current_number is placed in the position magic[row,column], m positions have been filled, so there are N-m empty positions left to be filled.
Let ๐ be the sum of the numbers already in the row or column or main diagonal (including current_number).
Let ๐ be the sum of the ๐โ๐ smallest numbers (from 1 to N*N) not yet entered into the magic square (according to the table used) and ๐ the sum of the ๐โ๐ largest numbers not yet entered (similarly) . If ๐=๐ then ๐=๐=0.
Let ๐ถ be the magic constant. If ๐ +๐>๐ถ or ๐ +๐<๐ถ, for some row or column or main diagonal to which magic[row, column] belongs, then current_number cannot be inserted into position magic[row,column ], i.e. the respective check_row(), check_column() and check_diagonals() will return false, otherwise they will all return true.
the txt external file has the following elements:
6
0 0 13 0 20 0
0 15 0 0 0 12
8 0 2 0 31 0
0 14 0 7 0 1
28 0 0 0 0 0
0 0 6 0 0 21
import java.io.*;
import java.util.*;
public class MainSolver{
static ArrayList<MagicSquare> stuckAL;
static Stack<MagicSquare> stuckST;
static LinkedList<MagicSquare> stuckLL;
static int datastructure;
static int N = 0;
static int[][] input;
public static void main() throws IOException {
//THE PROGRAM READS THE EXTERNAL FILE
Scanner sc = new Scanner(System.in);
System.out.print("Enter the file name: ");
String fileName = sc.next();
System.out.println("Enter data structure to use: (arraylist, stack, queue, linkedlist): ");
System.out.println("1: arraylist");
System.out.println("2: stack");
System.out.println("3: queue");
System.out.println("4: linkedlist");
datastructure = sc.nextInt();
File file = new File(fileName);
Scanner fileScanner = new Scanner(file);
N = fileScanner.nextInt();
input = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
input[i][j] = fileScanner.nextInt();
}
}
MagicSquare.size = N;
MagicSquare ms = new MagicSquare();
for(int i=0; i<N ;i++){
for(int j=0; j<N ;j++){
ms.set_cell(i,j,input[i][j]);
if (ms.magic[i][j] != 0) {
ms.used[ms.magic[i][j]-1] = true;
}
}
}
ms.check_used();
//PRINTING THE INPUT AND MAGIC ARRAY
System.out.println("Size of array from file: "+N);
ms.display(input);
System.out.println();
System.out.println("Size of array from MagicSquare object: "+ms.N);
ms.display(ms.magic);
fileScanner.close();
//IT STARTS THE INITIALIZATION OF DATASTRUCTURES & START THE SEARCH OF SUCCESSORS
initialize_search(ms,datastructure);
search(datastructure);
}
//THIS PART OF CODE NEEDS TO STAY AS IT IS. CAN'T MAKE CHANGES
static void initialize_search(MagicSquare ms, int datastructure) {
switch (datastructure) {
case 1:
case 2:
stuckAL = new ArrayList();
stuckAL.add(ms);
break;
case 3:
stuckST=new Stack();
stuckST.push(ms);
break;
case 4:
stuckLL=new LinkedList();
stuckLL.add(ms);
break;
default:
break;
}
}
//THIS PART OF CODE NEEDS TO STAY AS IT IS. CAN'T MAKE CHANGES
static void search(int datastructure) {
MagicSquare current = null, next;
switch (datastructure) {
case 1:
System.out.println("Search using ArrayList as a Stack");
break;
case 2:
System.out.println("Search using ArrayList as a Queue");
break;
case 3:
System.out.println("Search using Stack as a Stack");
break;
case 4:
System.out.println("Search using LinkedList as a Queue");
break;
default:
break;
}
boolean empty_frontier=false;
while (!empty_frontier) {
if (datastructure == 1) {
current = stuckAL.get(stuckAL.size()-1);
stuckAL.remove(stuckAL.size()-1);
}
else if (datastructure == 2) {
current = stuckAL.get(0);
stuckAL.remove(0);
}
else if (datastructure == 3)
current = stuckST.pop();
else if (datastructure == 4)
current = stuckLL.removeFirst();
current.initialize_successors();
while((next=current.next_successor()) != null)
{
if (next.numbers == N*N)
{
System.out.println("SOLUTION FOUND ");
System.out.println("==============");
next.display(next.magic);
return;
}
else switch (datastructure) {
case 1: ;
case 2: stuckAL.add(next);
break;
case 3: stuckST.push(next);
break;
case 4: stuckLL.addLast(next);
break;
}
}
switch (datastructure) {
case 1:
if (stuckAL.isEmpty())
empty_frontier=true;
break;
case 2:
if (stuckAL.isEmpty())
empty_frontier=true;
break;
case 3:
if (stuckST.isEmpty())
empty_frontier=true;
break;
case 4:
if (stuckLL.isEmpty())
empty_frontier=true;
break;
}
}
System.out.println("MAGIC SQUARES CANNOT BE CREATED");
}
}
class MagicSquare {
public static int size;
public int N;
public int C;
public int[][] magic;
public boolean[] used;
public int numbers;
public int row;
public int column;
public int current_number;
//THIS CONSTRUCTOR WITHOUT ARGUMENTS INITIALIZE N and C, the magic array and the numbers variable with zeros, as well as the used array with false values.
public MagicSquare() {
this.N = size;
C = N*((N*N+1)/2);
magic = new int[N][N];
used = new boolean[N*N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
magic[i][j] = 0;
}
}
for (int i = 0; i < used.length; i++) {
used[i] = false;
}
numbers = 0;
row = 0;
column = 0;
current_number = 0;
}
//THIS CONSTRUCTOR creates a copy of the object (mainly regarding the N, C, magic, numbers and used variables)
public MagicSquare(MagicSquare ms) {
N = ms.N;
C = ms.C;
magic = new int[N][N];
used = new boolean[N*N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
magic[i][j] = ms.magic[i][j];
}
}
for (int i = 0; i < used.length; i++) {
used[i] = ms.used[i];
}
numbers = ms.numbers;
row = ms.row;
column = ms.column;
current_number = ms.current_number;
}
//METHOD THAT IS CALLED TO FILL EACH CELL OF MAGIC ARRAY WITH NUMBER FROM EXTERNAL FILE
public void set_cell(int row, int col, int number){
if (number>=1 && number<=N*N && row>=0 && row<N*N && col>=0 && col<N*N && magic[row][col]==0){
magic[row][col] = number;
numbers++;
}
}
//METHOD THAT: "initializes" the process of constructing the "successors" of a MagicSquare object. As a successor we characterize a new object, which is in principle the same as its "parent" (with regard to the fields magic, numbers and used), but has an additional position of the magic square filled in in a valid way. The initialize_successors() method will practically give as values to the row and column fields the row and column of the next null of the magic table, while in addition it will initialize the value of the current_number field (eg, to 0).
public void initialize_successors() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (magic[i][j] == 0) {
row = i;
column = j;
current_number = 0;
return;
}
}
}
}
//METHOD THAT: each time it is called it will find the next value of current_number that can be placed in magic[row,column], construct an object that is a copy of the current object, but with the current_number in magic[row,column], and will return it. If no next value of current_number is found that can be inserted into magic[row, column], it will return null. In order for the current value of current_number to be inserted in the magic[row, column] position, this value must not already be used in the magic square (checked via the used table), and the methods check_row(), check_column() and check_diagonals() to return true.
public MagicSquare next_successor() {
MagicSquare successor;
while (current_number < N*N) {
current_number++;
if (!used[current_number-1] && check_row() && check_column() && check_diagonals()) {
successor = new MagicSquare(this);
successor.magic[row][column] = current_number;
successor.used[current_number-1] = true;
successor.numbers++;
/*if(column == N-1) {
successor.row++;
successor.column = 0;
}
else {
successor.column++;
}*/
System.out.println("next successor returns successor!");
return successor;
}
//break;
}
System.out.println("next successor returns null!");
return null;
}
//METHOD THAT: returns true if current_number is consistent with the row numbers of magic[row,column], otherwise returns false.
public boolean check_row(){
int sum = current_number;
int m = numbers;
int emptyPositions = N - m;
int a = getSumOfSmallestElementsNotUsed();
int b = getSumOfLargestElementsNotUsed();
System.out.println();
System.out.println("current number being tested in row: "+current_number);
for (int i = 0; i < N; i++) {
if (magic[row][i] != 0) {
sum += magic[row][i];
}
}
System.out.println("sum of numbers in row: "+sum);
if (sum + a > C || sum + b < C) {
System.out.println("row gives false!");
return false;
}
System.out.println("row gives true!");
return true;
}
//METHOD THAT: returns true if current_number is consistent with the column numbers of magic[row,column], otherwise returns false.
public boolean check_column(){
int sum = current_number;
int m = numbers;
int emptyPositions = N - m;
int a = getSumOfSmallestElementsNotUsed();
int b = getSumOfLargestElementsNotUsed();
System.out.println("current number being tested in column: "+current_number);
for (int i = 0; i < N; i++) {
if (magic[i][column] != 0) {
sum += magic[i][column];
}
}
System.out.println("sum of numbers in column: "+sum);
if (sum + a > C || sum + b < C) {
System.out.println("column gives false!");
return false;
}
System.out.println("column gives true!");
return true;
}
//METHOD THAT: which will return true if current_number is consistent with the numbers of each of the two main diagonals of the magic square, provided that magic[row,column] belongs to one or the other or both of the main diagonals of the magic square respectively, otherwise it will return false.
public boolean check_diagonals(){
int sum = current_number;
int m = numbers;
int emptyPositions = N - m;
int a = getSumOfSmallestElementsNotUsed();
int b = getSumOfLargestElementsNotUsed();
System.out.println("current number being tested in diagonals: "+current_number);
if (row == column) { //main diagonal
for (int i = 0; i < N; i++) {
if (magic[i][i] != 0) {
sum += magic[i][i];
}
}
} else if (row == N-column-1) { //other diagonal
for (int i = 0; i < N; i++) {
if (magic[i][N-i-1] != 0) {
sum += magic[i][N-i-1];
}
}
}
System.out.println("sum of numbers in diagonal: "+sum);
if (sum + a > C || sum + b < C) {
System.out.println("diagonals gives false!");
return false;
}
System.out.println("diagonals gives true!");
return true;
}
//METHOD THAT: calculate the sum of the 2 first empty elements of used array and therefore the smallest
public int getSumOfSmallestElementsNotUsed(){
int sum = 0;
int count = 0;
for (int i = 0; i < used.length; i++) {
if (!used[i]) {
sum += (i + 1);
count++;
}
if (count == 2) {
break;
}
}
System.out.println("sum of 2 smallest elements: "+sum);
return sum;
}
//METHOD THAT: calculate the sum of the 2 last empty elements of used array and therefore the largest
public int getSumOfLargestElementsNotUsed(){
int sum = 0;
int count = 0;
for (int i = used.length - 1; i >= 0; i--) {
if (!used[i]) {
sum += (i + 1);
count++;
}
if (count == 2) {
break;
}
}
System.out.println("sum of 2 largest elements: "+sum);
return sum;
}
public boolean isComplete() {
return numbers == N*N;
}
public void display(int array[][]) {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
public void check_used(){
int i,j;
int k=0;
for(i=0; i<magic.length; i++){
for(j=0; j<magic[i].length; j++){
System.out.println("POSITION IN USED ARRAY: "+k+" WITH VALUE: "+used[k]+" FROM POSITION IN MAGIC ARRAY: "+i+","+j+" WITH VALUE: "+magic[i][j]);
k++;
}
}
}
}
What do you think this computes?
this.N = size;
C = N*((N*N+1)/2); // C = 108
The size is 6 for your problem.
So you will need the values 1 thru 36 inclusive.
let max = N*N. So the sum of 1 thru 36 is max*(max+1)/2.
divide by N to get the col or row sum and you ((max*(max+1))/2)/N = 111.
or (N*(max+1))/2)
in your case is should have been (N*(N*N+1))/2.
The issue was that. (N*N+1) is 37. Then you divide by 2 which drops the fraction (int arithemetic). You need to first multiply by N and then divide by 2.
I am trying to find patterns that:
occur more than once
are more than 1 character long
are not substrings of any other known pattern
without knowing any of the patterns that might occur.
For example:
The string "the boy fell by the bell" would return 'ell', 'the b', 'y '.
The string "the boy fell by the bell, the boy fell by the bell" would return 'the boy fell by the bell'.
Using double for-loops, it can be brute forced very inefficiently:
ArrayList<String> patternsList = new ArrayList<>();
int length = string.length();
for (int i = 0; i < length; i++) {
int limit = (length - i) / 2;
for (int j = limit; j >= 1; j--) {
int candidateEndIndex = i + j;
String candidate = string.substring(i, candidateEndIndex);
if(candidate.length() <= 1) {
continue;
}
if (string.substring(candidateEndIndex).contains(candidate)) {
boolean notASubpattern = true;
for (String pattern : patternsList) {
if (pattern.contains(candidate)) {
notASubpattern = false;
break;
}
}
if (notASubpattern) {
patternsList.add(candidate);
}
}
}
}
However, this is incredibly slow when searching large strings with tons of patterns.
You can build a suffix tree for your string in linear time:
https://en.wikipedia.org/wiki/Suffix_tree
The patterns you are looking for are the strings corresponding to internal nodes that have only leaf children.
You could use n-grams to find patterns in a string. It would take O(n) time to scan the string for n-grams. When you find a substring by using a n-gram, put it into a hash table with a count of how many times that substring was found in the string. When you're done searching for n-grams in the string, search the hash table for counts greater than 1 to find recurring patterns in the string.
For example, in the string "the boy fell by the bell, the boy fell by the bell" using a 6-gram will find the substring "the boy fell by the bell". A hash table entry with that substring will have a count of 2 because it occurred twice in the string. Varying the number of words in the n-gram will help you discover different patterns in the string.
Dictionary<string, int>dict = new Dictionary<string, int>();
int count = 0;
int ngramcount = 6;
string substring = "";
// Add entries to the hash table
while (count < str.length) {
// copy the words into the substring
int i = 0;
substring = "";
while (ngramcount > 0 && count < str.length) {
substring[i] = str[count];
if (str[i] == ' ')
ngramcount--;
i++;
count++;
}
ngramcount = 6;
substring.Trim(); // get rid of the last blank in the substring
// Update the dictionary (hash table) with the substring
if (dict.Contains(substring)) { // substring is already in hash table so increment the count
int hashCount = dict[substring];
hashCount++;
dict[substring] = hashCount;
}
else
dict[substring] = 1;
}
// Find the most commonly occurrring pattern in the string
// by searching the hash table for the greatest count.
int maxCount = 0;
string mostCommonPattern = "";
foreach (KeyValuePair<string, int> pair in dict) {
if (pair.Value > maxCount) {
maxCount = pair.Value;
mostCommonPattern = pair.Key;
}
}
I've written this just for fun. I hope I have understood the problem correctly, this is valid and fast enough; if not, please be easy on me :) I might optimize it a little more I guess, if someone finds it useful.
private static IEnumerable<string> getPatterns(string txt)
{
char[] arr = txt.ToArray();
BitArray ba = new BitArray(arr.Length);
for (int shingle = getMaxShingleSize(arr); shingle >= 2; shingle--)
{
char[] arr1 = new char[shingle];
int[] indexes = new int[shingle];
HashSet<int> hs = new HashSet<int>();
Dictionary<int, int[]> dic = new Dictionary<int, int[]>();
for (int i = 0, count = arr.Length - shingle; i <= count; i++)
{
for (int j = 0; j < shingle; j++)
{
int index = i + j;
arr1[j] = arr[index];
indexes[j] = index;
}
int h = getHashCode(arr1);
if (hs.Add(h))
{
int[] indexes1 = new int[indexes.Length];
Buffer.BlockCopy(indexes, 0, indexes1, 0, indexes.Length * sizeof(int));
dic.Add(h, indexes1);
}
else
{
bool exists = false;
foreach (int index in indexes)
if (ba.Get(index))
{
exists = true;
break;
}
if (!exists)
{
int[] indexes1 = dic[h];
if (indexes1 != null)
foreach (int index in indexes1)
if (ba.Get(index))
{
exists = true;
break;
}
}
if (!exists)
{
foreach (int index in indexes)
ba.Set(index, true);
int[] indexes1 = dic[h];
if (indexes1 != null)
foreach (int index in indexes1)
ba.Set(index, true);
dic[h] = null;
yield return new string(arr1);
}
}
}
}
}
private static int getMaxShingleSize(char[] arr)
{
for (int shingle = 2; shingle <= arr.Length / 2 + 1; shingle++)
{
char[] arr1 = new char[shingle];
HashSet<int> hs = new HashSet<int>();
bool noPattern = true;
for (int i = 0, count = arr.Length - shingle; i <= count; i++)
{
for (int j = 0; j < shingle; j++)
arr1[j] = arr[i + j];
int h = getHashCode(arr1);
if (!hs.Add(h))
{
noPattern = false;
break;
}
}
if (noPattern)
return shingle - 1;
}
return -1;
}
private static int getHashCode(char[] arr)
{
unchecked
{
int hash = (int)2166136261;
foreach (char c in arr)
hash = (hash * 16777619) ^ c.GetHashCode();
return hash;
}
}
Edit
My previous code has serious problems. This one is better:
private static IEnumerable<string> getPatterns(string txt)
{
Dictionary<int, int> dicIndexSize = new Dictionary<int, int>();
for (int shingle = 2, count0 = txt.Length / 2 + 1; shingle <= count0; shingle++)
{
Dictionary<string, int> dic = new Dictionary<string, int>();
bool patternExists = false;
for (int i = 0, count = txt.Length - shingle; i <= count; i++)
{
string sub = txt.Substring(i, shingle);
if (!dic.ContainsKey(sub))
dic.Add(sub, i);
else
{
patternExists = true;
int index0 = dic[sub];
if (index0 >= 0)
{
dicIndexSize[index0] = shingle;
dic[sub] = -1;
}
}
}
if (!patternExists)
break;
}
List<int> lst = dicIndexSize.Keys.ToList();
lst.Sort((a, b) => dicIndexSize[b].CompareTo(dicIndexSize[a]));
BitArray ba = new BitArray(txt.Length);
foreach (int i in lst)
{
bool ok = true;
int len = dicIndexSize[i];
for (int j = i, max = i + len; j < max; j++)
{
if (ok) ok = !ba.Get(j);
ba.Set(j, true);
}
if (ok)
yield return txt.Substring(i, len);
}
}
Text in this book took 3.4sec in my computer.
Suffix arrays are the right idea, but there's a non-trivial piece missing, namely, identifying what are known in the literature as "supermaximal repeats". Here's a GitHub repo with working code: https://github.com/eisenstatdavid/commonsub . Suffix array construction uses the SAIS library, vendored in as a submodule. The supermaximal repeats are found using a corrected version of the pseudocode from findsmaxr in Efficient repeat finding via suffix arrays
(BecherโDeymonnazโHeiber).
static void FindRepeatedStrings(void) {
// findsmaxr from https://arxiv.org/pdf/1304.0528.pdf
printf("[");
bool needComma = false;
int up = -1;
for (int i = 1; i < Len; i++) {
if (LongCommPre[i - 1] < LongCommPre[i]) {
up = i;
continue;
}
if (LongCommPre[i - 1] == LongCommPre[i] || up < 0) continue;
for (int k = up - 1; k < i; k++) {
if (SufArr[k] == 0) continue;
unsigned char c = Buf[SufArr[k] - 1];
if (Set[c] == i) goto skip;
Set[c] = i;
}
if (needComma) {
printf("\n,");
}
printf("\"");
for (int j = 0; j < LongCommPre[up]; j++) {
unsigned char c = Buf[SufArr[up] + j];
if (iscntrl(c)) {
printf("\\u%.4x", c);
} else if (c == '\"' || c == '\\') {
printf("\\%c", c);
} else {
printf("%c", c);
}
}
printf("\"");
needComma = true;
skip:
up = -1;
}
printf("\n]\n");
}
Here's a sample output on the text of the first paragraph:
Davids-MBP:commonsub eisen$ ./repsub input
["\u000a"
," S"
," as "
," co"
," ide"
," in "
," li"
," n"
," p"
," the "
," us"
," ve"
," w"
,"\""
,"โ"
,"("
,")"
,". "
,"0"
,"He"
,"Suffix array"
,"`"
,"a su"
,"at "
,"code"
,"com"
,"ct"
,"do"
,"e f"
,"ec"
,"ed "
,"ei"
,"ent"
,"ere's a "
,"find"
,"her"
,"https://"
,"ib"
,"ie"
,"ing "
,"ion "
,"is"
,"ith"
,"iv"
,"k"
,"mon"
,"na"
,"no"
,"nst"
,"ons"
,"or"
,"pdf"
,"ri"
,"s are "
,"se"
,"sing"
,"sub"
,"supermaximal repeats"
,"te"
,"ti"
,"tr"
,"ub "
,"uffix arrays"
,"via"
,"y, "
]
I would use KnuthโMorrisโPratt algorithm (linear time complexity O(n)) to find substrings. I would try to find the largest substring pattern, remove it from the input string and try to find the second largest and so on. I would do something like this:
string pattern = input.substring(0,lenght/2);
string toMatchString = input.substring(pattern.length, input.lenght - 1);
List<string> matches = new List<string>();
while(pattern.lenght > 0)
{
int index = KMP(pattern, toMatchString);
if(index > 0)
{
matches.Add(pattern);
// remove the matched pattern occurences from the input string
// I would do something like this:
// 0 to pattern.lenght gets removed
// check for all occurences of pattern in toMatchString and remove them
// get the remaing shrinked input, reassign values for pattern & toMatchString
// keep looking for the next largest substring
}
else
{
pattern = input.substring(0, pattern.lenght - 1);
toMatchString = input.substring(pattern.length, input.lenght - 1);
}
}
Where KMP implements KnuthโMorrisโPratt algorithm. You can find the Java implementations of it at Github or Princeton or write it yourself.
PS: I don't code in Java and it is quick try to my first bounty about to close soon. So please don't give me the stick if I missed something trivial or made a +/-1 error.
I should carry out this exercise in the creation of a class, I uploaded this is the professor's solution, in sum and product methods can not quite figure out what place and why use "A".
class Vettore {
private int[] V = new int[6];
public Vettore(int[] X) {
if (X.length != 6)
throw new BadDataException();
for (int i = 0; i < 6; i++)
if (X[i] < 0)
throw new BadDataException();
else
V[i] = X[i];
}
public Vettore() {}
public Vettore somma(Vettore X) {
int[] A = new int[6];
for (int i = 0; i < 6; i++)
A[i] = V[i] + X.V[i];
return new Vettore(A);
}
public Vettore prodotto(Vettore X) {
int k = 0;
for (int i = 0; i < 6; i++)
k += V[i] * X.V[i];
return k;
}
public int get(int i) {
if (i < 0 || i > 5)
throw new BadDataException();
return V[i];
}
public String toString() {
String t = "( ";
for (int i = 0; i < 6; i++)
t += V[i] + (i == 5 ? " " : ", ");
return t + ")";
}
public boolean equals(Vettore X) {
for (int i = 0; i < 6; i++)
if (V[i] != X.V[i])
return false;
return true;
}
}
As far as I see it, and assuming somma means sum and prodotto means product, The A is needed because you have to store the sum values of the V and X.V arrays for every index. If you didn't use another array for this, you wouldn't be able to achive adding the appropriate indexes in somma for example. This method stands for - as I see it - Adding the two arrays' appropriate elements.
EDIT: another thing. Are you sure that the return types match variables to return? I elaborated the use of somma but didn't pay attention that prodotto has a wrong return type, just as it was said in the comments.
You might want to correct the prodotto method definition as -
public Vettore prodotto(Vettore X) {
int[] K = new int[6]; // deault values are 0
for (int i = 0; i < 6; i++)
K[i] += V[i] * X.V[i];
return new Vettore(K);
}
This would evaluate the product of the array field V for two instances of class Vettore namingly X the input param and the current instance that you would call the method from.
return new Vettore(K); creates a new instance of Vettore class with K as arrays field, while executing the constructor logic in place as follows -
public SumAndProductExercise(int[] X) {
if (X.length != 6) { // length of the array is 6 or not
throw new BadDataException();
}
for (int i = 0; i < 6; i++) {
if (X[i] < 0) { // all the elements of array are >=0 or not
throw new BadDataException();
} else {
V[i] = X[i]; // the field on the new instance
}
}
}
I have written a program in which you can sort an ArrayList using 3 different sort methods: bubble, merge and bogo (or stupid sort). Here's the code:
import java.util.*;
import java.io.*;
import java.lang.*;
import java.lang.IndexOutOfBoundsException;
public class Sorting {
public static void bubbleSort(ArrayList<Integer> bubble) {
int temp;
if (bubble.size() > 1) {
for (int i = 0; i < bubble.size(); i++) {
for (int j = 0; j < bubble.size() - i - 1; j++) {
if (bubble.get(i).compareTo(bubble.get(i + 1)) > 0) {
temp = bubble.get(i);
bubble.set(i, bubble.get(i + 1));
bubble.set(i + 1, temp);
}
}
}
}
}
public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
if (merge.size() == 1) {
return merge;
} else {
int halfway = merge.size() / 2;
ArrayList<Integer> left = new ArrayList<Integer>(halfway);
ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);
for (int i = 0; i < halfway; i++) {
left.add(merge.get(i));
}
for (int i = halfway; i < merge.size(); i++) {
right.add(merge.get(i));
}
left = mergeSort(left);
right = mergeSort(right);
ArrayList<Integer> newMerge = new ArrayList<Integer>(merge.size());
int index1 = 0;
int index2 = 0;
for (int i = 0; i < merge.size(); i++) {
if (index1 == left.size()) {
merge.set(i, right.get(index2));
index2++;
} else if (index2 == right.size()) {
merge.set(i, left.get(index1));
index1++;
} else {
if (left.get(index1) <= right.get(index2)) {
newMerge.set(i, left.get(index1));
index1++;
} else if (left.get(index1) >= right.get(index2)) {
newMerge.set(i, right.get(index2));
index2++;
}
}
}
return newMerge;
}
}
public static void bogoSort(ArrayList<Integer> bogo) {
while (!isOrdered(bogo)) {
Collections.shuffle(bogo);
}
}
public static boolean isOrdered(ArrayList<Integer> order) {
for (int i = 0; i < order.size(); i++) {
if (order.get(i) > order.get(i + 1)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
try {
Scanner input = new Scanner(new File("random1.txt"));
ArrayList<Integer> random = new ArrayList<Integer>();
while (input.hasNextInt()) {
random.add(input.nextInt());
}
input.close();
System.out.println("Unsorted: " + random);
long startTime = System.nanoTime();
bubbleSort(random);
long endTime = System.nanoTime();
long duration = ((endTime - startTime) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Bubble sort took: " + duration + " milliseconds to sort.");
System.out.println();
long startTime2 = System.nanoTime();
mergeSort(random);
long endTime2 = System.nanoTime();
long duration2 = ((endTime2 - startTime2) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Merge sort took: " + duration2 + " milliseconds to sort.");
System.out.println();
long startTime3 = System.nanoTime();
bogoSort(random);
long endTime3 = System.nanoTime();
long duration3 = ((endTime3 - startTime3) / 1000000);
System.out.println("Sorted: " + random);
System.out.println("Bogo sort took: " + duration3 + " milliseconds to sort.");
System.out.println();
} catch (FileNotFoundException e) {
System.out.println("File is not found.");
System.exit(1);
}
}
}
When I ran the program, the unsorted ArrayList and the bubble sort method showed up but I received an error with my Merge Sort method, which stated that I have an IndexOutOfBoundsException at lines 38, 57 & 102. I did the algorithm correctly but I don't know why I'm receiving an error. Any reasoning behind this?
To List, you can not add or set element, at specific index, if the index is greater than the size. Check the documentation here. You can add null values to your List(newMerge) to fix this or simply add elements to your newMerge list. I prefer later. The other IndexOutOfBoundsException exceptions are related to this.
Corrected Code
public static ArrayList<Integer> mergeSort(ArrayList<Integer> merge) {
if (merge.size() == 1) {
return merge;
} else {
int halfway = merge.size() / 2;
ArrayList<Integer> left = new ArrayList<Integer>(halfway);
ArrayList<Integer> right = new ArrayList<Integer>(merge.size() - halfway);
for (int i = 0; i < halfway; i++) {
left.add(merge.get(i));
}
for (int i = halfway; i < merge.size(); i++) {
right.add(merge.get(i));
}
left = mergeSort(left);
right = mergeSort(right);
int index1 = 0;
int index2 = 0;
// Merge left and right sub-lists into original list
// See how the newMerge list is no longer needed
for (int i = 0; i < merge.size(); i++) {
if (index1 == left.size()) {
merge.set(i, right.get(index2));
index2++;
} else if (index2 == right.size()) {
merge.set(i, left.get(index1));
index1++;
} else {
if (left.get(index1) <= right.get(index2)) {
merge.set(i, left.get(index1)); // We now set the values into merge
index1++;
} else if (left.get(index1) >= right.get(index2)) {
merge.set(i, right.get(index2)); // We now set the values into merge
index2++;
}
}
}
return merge; // We now return a reference to merge, not newMerge
}
}
public static boolean isOrdered(ArrayList<Integer> order) {
for (int i = 0; i < order.size() - 1; i++) { // order.size() - 1 prevents going out of bounds
if (order.get(i) > order.get(i + 1)) {
return false;
}
}
return true;
}
Elaboration
Issues with mergeSort()
The issue arises when you begin merging your left and right sub-lists. Note that during the merging process you invoke the set() method on both the newMerge and merge lists. This isn't what you want. Within the "merge"-loop you may attempt to set a value into the newMerge list when it is empty, or when i is greater than its size. This is the reason for the error you're getting. Since your other sorts seem to sort the original list that was passed in (versus creating a copy, sorting, and returning the copy instead) I can assume your merge sort was intended to do the same. If that's the case, there isn't actually a need for a newMerge list at all, since we can just write into the original merge list. This change can be seen in the code above.
Issues with isOrdered()
Minor issue here. You should have terminated your loop when i == order.size() - 1, not when i == order.size(). Otherwise, when i == order.size() - 1, order.get(i + 1) will attempt to retrieve an element that does not exist within the list (i.e. out of bounds).
I did the algorithm correctly but I don't know why I'm receiving an error.
Clearly, you haven't done the algorithm correctly, or you wouldn't be getting the exception. ;-)
You are calling:
merge.set(i, right.get(index2));
and
merge.set(i, left.get(index1));
which is modifying the original list, not your newly created newMerge list which is returned from mergeSort. The caller expects the returned list to have as many elements as it was passed, but (since it is never modified) it actually has zero, which results in the exception in the caller.
Use newMerge as the target of your set calls, and use add instead of trying to set at a particular index.
I have two ArrayLists of String type and want to mix them as follows:
SPK = [A,A,A,B,A,A,A,A,A,B] and
DA= [ofm,sd,sd,sd,sd,sd,sd,sd,sd,sv]
I need to create some String in other ArrayList as below:
SPK_DA = [ofmAsdAsdAB, sdBA, sdAsdAsdAsdAsdAB]
in this set I need to equate previous similar elements before turning (from A to B) occur in SPK array.
I wrote a program but it adds one extra sdA (I don't know why I can't do such a simple thing).
for (int i=0; i <SPK.size()-1; i++){
if (SPK.get(i)==SPK.get(i+1) && (i+1)<= SPK.size()){
speakerChain = DA.get(i)+SPK.get(i);
speakerChain1=DA.get(i+1)+SPK.get(i+1);
SPKTrace.add(speakerChain);
SPKTrace.add(speakerChain1);
}else if (SPK.get(i)!=SPK.get(i+1)){
if (SPKTrace.size()!=0){
SPKTrace.add(SPK.get(i+1));
//SPKString = removeDuplicates (SPKTrace);
String S1 = arrayTostring(SPKTrace);
SPKResource.add(S1);
SPKTrace.clear();
}else {
SPKTrace.add(DA.get(i)+SPK.get(i)+SPK.get(i+1));
//SPKString = removeDuplicates (SPKTrace);
String S1 = arrayTostring(SPKTrace);
SPKResource.add(S1);
SPKTrace.clear();
}
}
}
}
}
System.out.println(SPKResource.toString());
My Output: [ofmAsdAsdAsdAB, sdBA, sdAsdAsdAsdAsdAsdAsdAsdAB]
When I use for loop it happens that it creates more sdAs....
Indicies.add(0);
for (int i = 0; i < SPK.size() - 1; i++) {
if (SPK.get(i) != SPK.get(i + 1)) {
Indicies.add(i + 1);
}
}
for (int i = 0; i < Indicies.size() - 1; i++) {
Count.add(Indicies.get(i + 1) - Indicies.get(i));
}
Count.add((SPK.size() - Indicies.get(Indicies.size() - 1)));
System.out.println("count:" + Count);
int counter = 0;
int newIndex =0;
for (int j = 1; j <= Count.size(); j++) {
String element = "";
for (int kk = 0; kk < (Count.get(j-1)); kk++) {
element = element + (DA.get(kk+newIndex) + SPK.get(kk+newIndex));
}
newIndex = newIndex+Count.get(j-1);
if (element.endsWith("A")){
SPKResource.add(element+"B");
} else if (element.endsWith("B")){
SPKResource.add(element+"A");
}
}
}
}
for (String S:SPKResource){
System.out.println(SPKResource);
}
The above code can give me the answer but I think it is quite inefficient. Is there any idea to make it more efficient?