Some Background
Last week I did a problem in my textbook where It told me to generate 20 random numbers and then put brackets around successive numbers that are equal
Consider the following which my program outputs
697342(33)(666)(44)69(66)1(88)
What I need to do
The next problem was to basically get the longest sequence of these words and put brackets around them. If you have
1122345(6666)
Basically you need to put brackets around four 6's , since they occur most often.
I've finished all other problems in the chapter I am studying ( Arrays and ArrayLists), however I can't seem to figure this one out.
Here is the solution that I have made for putting brackets around successive numbers:
class Seq
{
private ArrayList<Integer> nums;
private Random randNum;
public Seq()
{
nums = new ArrayList<Integer>();
randNum = new Random();
}
public void fillArrList()
{
for (int i = 0 ; i < 20 ; i++)
{
int thisRandNum = randNum.nextInt(9)+1;
nums.add(thisRandNum);
}
}
public String toString() {
StringBuilder result = new StringBuilder();
boolean inRun = false;
for (int i = 0; i < nums.size(); i++) {
if (i < nums.size() - 1 && nums.get(i).equals(nums.get(i + 1))) {
if (!inRun) {
result.append("(");
}
result.append(nums.get(i));
inRun = true;
} else {
result.append(nums.get(i));
if (inRun) {
result.append(")");
}
inRun = false;
}
}
return result.toString();
}
}
My Thoughts
Iterate through the whole list. Make a count variable, that keeps track of how many numbers are successive of each other. I.e 22 would have a count of 2. 444 a count of 3
Next make an oldCount, which compares the current count to the oldCount. We only want to keep going if our new count is greater than oldCount
After that we need a way to get the starting index of the largest count variable, as well as the end.
Is my way of thinking correct? Because I'm having trouble updating the oldCount and count variable while comparing them, since there values constantly change. I'm not looking for the code, but rather some valuable hints.
My count is resetting like this
int startIndex, endIndex = 0;
int count = 0;
int oldCount = 0;
for(int i = 0 ; i < nums.size(); i++)
{
if(nums.get(i) == nums.get(i+1) && count >= oldCount)
{
count++;
}
oldCount = count;
}
Only after walking all elements you will know the longest subsequence.
11222333333444555
11222(333333)444555
Hence only after the loop you can insert both brackets.
So you have to maintain a local optimum: start index plus length or last index of optimum.
And then for every sequence the start index of the current sequence.
As asked:
The optimal state (sequence) and the current state are two things. One cannot in advance say that any current state is the final optimal state.
public String toString() {
// Begin with as "best" solution the empty sequence.
int startBest = 0; // Starting index
int lengthBest = 0; // Length of sequence
// Determine sequences:
int startCurrent = 0; // Starting index of most current/last sequence
for (int i = 0; i < nums.size(); i++) {
// Can we add the current num to the current sequence?
if (i == startCurrent || nums.get(i).equals(nums.get(i - 1)))) {
// We can extend the current sequence with this i:
int lengthCurrent = i - startCurrent + 1;
if (lengthCurrent > lengthBest) { // Current length better?
// New optimum:
startBest = startCurrent;
lengthBest = lengthCurrent;
}
} else {
// A different num, start here.
// As we had already a real sequence (i != 0), no need for
// checking for a new optimum with length 1.
startCurrent = i;
}
}
// Now we found the best solution.
// Create the result:
StringBuilder result = new StringBuilder();
for (int i = 0; i < nums.size(); i++) {
result.append(nums.get(i));
}
// Insert the right ')' first as its index changes by 1 after inserting '('.
result.insert(startBest + lengthBest, ")");
result.insert(startBest, "(");
return result.toString();
}
The first problem is how to find the end of a sequence, and set the correct start of the sequence.
The problem with the original algorithm is that there is handled just one sequence (one subsequence start).
The way you have suggested could work. And then, if newcount is greater than oldcount, you'll want to store an additional number in another variable - the index of the where the longest sequence begins.
Then later, you can go and insert the ( at the position of that index.
i.e. if you have 11223456666.
The biggest sequence starts with the first number 6. That is at index 7, so store that 7 in a variable.
I think you need to iterate the entire list even though the current count is lower than the oldCount, what about e.g. 111224444?
Keep 4 variables while iterating the list: highestStartIndex, highestEndIndex, highestCount and currentCount. Iterate the entire list and use currentCount to count equal neighbouring numbers. Update the highest* variables when a completed currentCount is higher than highestCount. Lastly write the numbers out with paranthesis using the *Index variables.
Related
Ok so I currently have a String array which contains keycodes, and i want to check if the first element shares common specifications with the second , e.g. [012] has similar elements with [123]. I currently loop through the length of the first element, and then loop through the length of the second element, and compare those two like this:
If(A[1].charAt(j) == A[2].charAt[i]) c++; c is a counter to show how many
common elements the keycodes have. Here is the method i created
static boolean hasSimilarity(String[] A, int K, int i){
int c = 0;
for(int j = 0;j<K;j++){
for(int m = j;m<K;m++){
if(A[i].charAt(j) == A[i+1].charAt(m)) c++;
}
}
return c != 0;
}
And here is the execution of it in the Main class:
int max = -1;
findSimilar FS = new findSimilar();
for (int i = 0; i < sum.length -1; i++) {
boolean hasSimilar = FS.hasSimilarity(key,K,i);
if (!hasSimilar) {
int summ = sum[i] + sum[i + 1];
System.out.println(summ);
if (summ > max) {
max = summ;
}
}
}
When i run this, i get a java.lang.StringIndexOutOfBoundsException out of range: 0 . What am I doing wrong? Is there any better way to compare two keycodes in order to find similarities beetween them?
This error:
java.lang.StringIndexOutOfBoundsException out of range: 0
Can only occur if one of your strings is the blank string "".
You are attempting to get charAt(0) when there is no char 0 (ie first char).
——-
You would avoid this problem, and have a far more efficient algorithm, if you first collected the counts of each character then compared those, which would have time complexity O(n), whereas your algorithm is O(n2) (albeit that it seems your n - the length of your inputs - is small).
I am trying to come up with a program that will search inside of an array that is given a length by the user that picks out whether there is a pair of numbers that sum to 7. The idea is that if there is k amount of dice being thrown, how many pairs of numbers out of those dice thrown add up to 7. So far this is all that I could come up with but I am very stuck.
This is the driver class for the program. I have to write a class that will make this driver function properly.
import java.util.Scanner;
public class SevenDriver{
public static void main(String[] args){
System.out.println("Enter number of dice to toss");
Scanner s = new Scanner(System.in);
int diceCount = s.nextInt();
SevenTally t = new SevenTally(diceCount);
int experiments = 1000000;
int wins = 0;
for(int j = 0; j < experiments; j++)
if(t.experiment()) wins++;
System.out.println((double)wins/experiments);
}
}
This is what I have so far. It does not currently work or compile. I am just looking for some ideas to get me going. Thanks!
public class SevenTally{
private int diceCount;
public SevenTally(int die){
diceCount = die;
}
public int genDice(){
return 1 + (int)(Math.random()*6);
}
public boolean experiment(){
boolean[] nums = new boolean[diceCount];
int ranNum;
int sum = 7;
for(int i = 0; i < nums.length; i++){
ranNum = genDice();
if (nums[ranNum] == sum){
return true;
}
}
int left = 0;
int right = nums.length - 1;
while(left<right){
int tempSum = nums[left] + nums[right];
if(tempSum == 7){
return true;
}
else if(tempSum>7){
right--;
}
return false;
}
}
First populate your array of length k with random int in [1;6]
The number of possible pairs in an array of length k is the number of 2-combinations in the array, which is (k-1)*k/2 (http://en.wikipedia.org/wiki/Combination)
You can test all the possible pairs (i,j) in your array like so:
int win = 0;
int tally = 7;
for(int i=0; i<k-1; i++){
for(int j=i+1; j<k; j++){
if(array[i]+array[j] == tally){
win++;
}
}
}
What this does is that it sets the first element of the pair to be the first element of the array, and sums it with the other elements one after the other.
It pairs array[0] with array[1] to array[k-1] at the first pass of the i for loop, that's k pairs.
Then k-1 pairs at second pass, and so on.
You end up with (k)+(k-1)+(k-2)+...+1 pairs, and that's exactly (k-1)*k/2 pairs.
done =]
edit: sorry, haven't read the whole thing. the method experiment() is supposed to return a boolean. you can return win>0?true:false; for example...
This Wiki page has some algorithms to do that. Its not a trivial problem...
You're generating a random number in ranNum, and then using it as an index into the array nums. Meanwhile, nums never gets filled, so no matter which box you index into, it never contains a 7.
What you want to do, if I understand your problem correctly, is fill each space in the array with the result of a die roll, then compare every two positions (rolls) to see if they sum to seven. You can do that using a nested for loop.
Essentially, you want to do this: (written in pseudocode as I'm not a java programmer)
int[] results[numrolls]
for (count = 0 to numrolls-1) { results[numrolls]=dieRoller() }
for (outer = 0 to numrolls-2)
for (inner = outer+1 to numrolls-1)
if (results[outer] + results[inner] == 7) return true
return false;
However, in this case there's an even easier way. You know that the only ways to get a sum of 7 on 2d6 are (1,6),(2,5),(3,4),(4,3),(5,2),(6,1). Set up a 6-length boolean array, roll your dice, and after each roll set res[result] to true. Then return (1-based array used for simplicity) ( (res[1] && res[6]) || (res[2] && res[5]) || (res[3] && res[4]) ).
ArrayIndexOutOfBoundsException means you are trying to access an element of the array that hasn't been allocated.
In your code, you create a new array d of length diceCount, but then you genDice() on always 6 elements.
I am trying to loop through an arraylist and gradually remove an element every 3 indices. Once it gets to the end of the arraylist I want to reset the index back to the beginning, and then loop through the arraylist again, again removing an element every 3 indices until there is only one element left in the arraylist.
The listOfWords is an array with a length of 3 that was previously filled.
int listIndex = 0;
do
{
// just to display contents of arraylist
System.out.println(listOfPlayers);
for(int wordIndex = 0; wordIndex < listOfWords.length; wordIndex++
{
System.out.print("Player");
System.out.print(listOfPlayers.get(wordIndex));
System.out.println("");
listIndex = wordIndex;
}
listOfPlayers.remove(listOfPlayers.get(listIndex));
}
while(listOfPlayers.size() > 1);
I have tried to implement for several hours yet I am still having trouble. Here's what happens to the elements of the arraylist:
1, 2, 3, 4
1, 2, 4
1, 2
Then it throws an 'index out of bounds error' exception when it checks for the third element (which no longer exists). Once it reaches the last element I want it to wrap around to the first element and continue through the array. I also want it to start where it left off and not from the beginning once it removes an element from the arraylist.
Maybe I have just missed the boat, but is this what you were after?
import java.util.ArrayList;
import java.util.Random;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
Random r = new Random();
//Populate array with ten random elements
for(int i = 0 ; i < 4; i++){
numbers.add(r.nextInt());
}
while(numbers.size() > 1){
for(int i = 0; i < numbers.size();i++){
if(i%3 == 0){//Every 3rd element should be true
numbers.remove(i);
}
}
}
}
}
You could move every third element to a temporary list then use List#removeAll(Collection) to remove the items when you finish each loop...until the master list was empty...
Lets back up and look at the problem algorithmically.
Start at the first item and start counting.
Go to the next item and increment your count. If there is no next item, go to the beginning.
If the count is '3', delete that item and reset count. (Or modulo.)
If there is one item left in the list, stop.
Lets write pseudocode:
function (takes a list)
remember what index in that list we're at
remember whether this is the item we want to delete.
loop until the list is size 1
increment the item we're looking at.
increment the delete count we're on
should we delete?
if so, delete!
reset delete count
are we at the end of the list?
if so, reset our index
Looking at it this way, it's fairly easy to translate this immediately into code:
public void doIt(List<String> arrayList) {
int index = 0;
int count = 0;
while(arrayList.size() != 1) {
index = index + 1;
count = count + 1; //increment count
String word = arrayList.get(index);//get next item, and do stuff with it
if (count == 3) {
//note that the [Java API][1] allows you to remove by index
arrayList.remove(index - 1);//otherwise you'll get an off-by-one error
count = 0; //reset count
}
if (index = arrayList.size()) {
index = 0; //reset index
}
}
}
So, you can see the trick is to think step by step what you're doing, and then slowly translate that into code. I think you may have been caught up on fixing your initial attempt: never be afraid to throw code out.
Try the following code. It keeps on removing every nth element in List until one element is left.
List<Integer> array = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
int nth = 3;
int step = nth - 1;
int benchmark = 0;
while (array.size() > 1) {
benchmark += step;
benchmark = benchmark > array.size() - 1 ? benchmark % array.size() : benchmark;
System.out.println(benchmark);
array.remove(array.get(benchmark));
System.out.println(array);
}
You could use a counter int k that you keep incrementing by three, like k += 3. However, before you use that counter as an index to kick out any array element, check if you already went beyond and if so, subtract the length of this array from your counter k. Also make sure, to break out of your loop once you find out the array has only one element left.
int k = -1;
int sz = list.length;
while (sz > 1)
{
k += 3;
if (k >= sz)
{
k -= sz;
}
list.remove(k);
sz --;
}
This examples shows that you already know right away how often you will evict an element, i.e. sz - 1 times.
By the way, sz % 3 has only three possible results, 0, 1, 2. With a piece of paper and a cup of coffee you can find out what the surviving element will be depending on that, without running any loop at all!
You could try using an iterator. It's late irl so don't expect too much.
public removeThirdIndex( listOfWords ) {
Iterator iterator = listOfWords.iterator
while( iterator.hasNext() ){
iterator.next();
iterator.next();
iterator.next();
iterator.remove();
}
}
#Test
public void tester(){
// JUnit test > main
List listOfWords = ... // Add a collection data structure with "words"
while( listOfWords.size() < 3 ) {
removeThirdIndex( listOfWords ); // collections are mutable ;(
}
assertTrue( listOfWords.size() < 3 );
}
I would simply set the removed to null and then skip nulls in the inner loop.
boolean continue;
do {
continue = false;
for( int i = 2; i < list.length; i += 3 ){
while( list.item(i++) == null && i < list.length );
Sout("Player " + list.item(--i) );
continue = true;
}
} while (continue);
I'd choose this over unjustified shuffling of the array.
(The i++ and --i might seem ugly and may be rewritten nicely.)
I want to find the majority in array (number that appears most of the time).
I have a sorted array and use these cycles:
for(int k = 1;k < length;k++)
{
if(arr[k-1] == arr[k])
{
count++;
if(count > max)
{
max = count;
maxnum = arr[k-1];
}
} else {
count = 0;
}
}
or
for(int h=0;h<length;h++)
{
for(int l=1;l<length;l++)
{
if(arr[h] == arr[l])
{
count++;
if(count > max)
{
max = count;
maxnum = arr[h];
}
} else count = 0;
}
}
they are similiar. When i try them on small arrays everything seems to be ok. But on a long run array with N elements 0<=N<=500000, each element K 0<=K<=10^9 they give wrong answers.
Here is solution with mistake http://ideone.com/y2gvnX. I know there are better algos to find majority but i just need to know where is my mistake.
I really can't find it :( Will really appreciate help!
First of all, you should use the first algorithm, as your array is sorted. 2nd algorithm runs through the array twice unnecessarily.
Now your first algorithm is almost correct, but it has two problems: -
The first problem is you are setting count = 0, in else part,
rather it should be set to 1. Because every element comes at least
once.
Secondly, you don't need to set max every time in your if. Just
increment count, till the if-condition is satisfied, and as soon
as condition fails, check for the current count with current
max, and reset the current max accordingly.
This way, your max will not be checked on every iteration, but only when a mismatch is found.
So, you can try out this code: -
// initialize `count = 1`, and `maxnum = Integer.MIN_VALUE`.
int count = 1;
int max = 0;
int maxnum = Integer.MIN_VALUE;
for(int k = 1;k < length;k++)
{
if(arr[k-1] == arr[k]) {
count++; // Keep on increasing count till elements are equal
} else {
// if Condition fails, check for the current count v/s current max
if (max < count) { // Move this from `if` to `else`
max = count;
maxnum = arr[k - 1];
}
count = 1; // Reset count to 1. As every value comes at least once.
}
}
Note : -
The problem with this approach is, if two numbers say - 1 and 3, comes equal number of times - which is max, then the max count will be counted for 3 (assuming that 3 comes after 1, and maxnum will contain 3 and ignore 1. But they both should be considered.
So, basically, you cannot use a for loop and maintain a count to take care of this problem.
A better way is to create a Map<Integer, Integer>, and store the count of each value in there. And then later on sort that Map on value.
Your first algorithm looks correct to me. The second one (which is what your linked code uses) needs some initialization each time through the loop. Also, the inner loop does not need to start at 1 each time; it can start at h + 1:
for(int h=0; h<length; h++)
{
count = 1; // for the element at arr[h]
for(int l=h + 1; l<length; l++)
{
if(arr[h] == arr[l])
{
count++;
}
}
if(count > max)
{
max = count;
maxnum = arr[h];
}
}
The first algorithm is much better for sorted arrays. Even for unsorted arrays, it would be cheaper to sort the array (or a copy of it) and then use the first algorithm rather than use the second.
Note that if there are ties (such as for the array [1, 1, 2, 2, 3] as per #Rohit's comment), this will find the first value (in the sort order) that has the maximum count.
The error I can readily see is that if all elements are distinct, then the max at end is 0.
However it has to be 1.
So when you update count in "else" case, update it to 1 instead of 0, as a new element has been discovered, and its count is 1.
Your first algorithm only makes sense if the array is sorted.
Your second algorithm just sets count to zero in the wrong place. You want to set count to zero before you enter the inner for loop.
for(int h=0;h<length;h++)
{
count = 0;
for(int l=0;l<length;l++)
{
if(arr[h] == arr[l])
{
count++;
if(count > max)
{
max = count;
maxnum = arr[h];
}
}
}
}
Also, you don't need to check count each time in the inner loop.
max = 0;
for(int h=0;h<length;h++)
{
count = 0;
for(int l=0;l<length;l++)
{
if(arr[h] == arr[l])
count++;
}
if(count > max)
{
max = count;
maxnum = arr[h];
}
}
I am working on an algorithm that has three parts. The first is a recursive method that will wrap words to a specific length with the least penalty. The second is an algorithm that is a Dynamic implementation of the recursive method. The last one is a Greedy Algorithm of the problem. I already have the Greedy one coded but I'm struggling on the Recursive solution. I'm not quite sure where exactly I'm running into an issue with my Recursive method but I know it should be something similar to the Knuth-Plass Algorithm. The recursive algorithm is supposed to have a factorial running time, and used more to help with the dynamic solution. If anyone has a link to a Knuth-Plass implementation or can spot something huge in my code, any help would be appreciated.
Recursive Algorithm:
public static ArrayList<String> recursive(ArrayList<String> input, int size) {
if(input.size() <= 1)
return input;
ArrayList<String> temp1 = input;
ArrayList<String> temp2 = input;
for(int i = 0; i < input.size(); i++) {
if(input.size() - 1 >= size)
break;
else {
for(int j = 0; j < input.size(); j++) {
temp1.set(j, temp1.get(j) + " " + temp1.get(j + 1));
temp1.remove(j + 1);
if(totalPenalty(blankChars(temp1, size)) < totalPenalty(blankChars(temp2, size))) {
input = recursive(temp1, size);
} else {
input = recursive(temp2, size);
}
}
}
}
return input;
}
The totalPenalty() and blankChars return the amount of penalty at the end of each line.
EDIT: I'm still not seeing any immediate solutions. Any help would be appreciated.
That looks like Java, and in Java there is no implicit copy-constructor.
ArrayList<String> temp1 = input; <-- this will not create another object with the same content, but instead a reference to the same object.
You need to change line 4 and 5 to:
ArrayList<String> temp1 = new ArrayList<String>(input);
ArrayList<String> temp2 = new ArrayList<String>(input);
I haven't looked for any other mistakes, so try this out and update the question if you have any more problems.
About the Knuth-Pass breaking algorithm; You can find a Python implementation at http://oedipus.sourceforge.net/texlib/. I haven't looked closer at it, but the description seems to be what you are looking for.
I hope the following code runs. Here I have added the cost for the last line as well. Though word processors use greedy algorithms most of the time and they neglect the cost of the last line. Let me know if this is clear to you.
import java.lang.Math;
public int RCS(int[] l , int n , int m , int index) {
// first base condition - if index gets beyond the array 'l' , then return 0;
if (index > n - 1) return 0;
// second base condition - if index is the last word i.e there is only one word left in the
// array to be inserted in the line then return the cost if added in that line.
if (index == n - 1) return (m - l[n - 1]) * (m - l[n - 1]) * (m - l[n - 1]);
// make a global cost variable to be returned
int cost = Integer.MAX_VALUE;
// Here , we try to select words from the array and apply RCS on the rest of the array.
// From index to last element , we iteratvely select first , or first two and so on.
for (int i = index ; i < n ; i++) {
int current_space_sum = 0 ;
// we add the length of the selected word. We have selected words in array from index to i.
for (int k = index ; k <= i ; k++) {
current_space_sum = current_space_sum + l[k] ;
}
// Adding the space between the words choses. If 2 words are chosen , there is one space and so on
current_space_sum = current_space_sum + i - index;
// If the length of the chosen words is greater than the line can accept , no need of looking beyond.
if (current_space_sum > m) break;
// Iteratively find the minimum cost
cost = Math.min(cost , (m - current_space_sum) * (m - current_space_sum) * (m - current_space_sum) + RCS(l , n , m , i + 1));
}
return cost;
}
public static void main(String[] args) {
WordWrap w = new WordWrap();
int[] l = {3, 2 , 2 , 5};
int n = l.length;
int m = 6;
int result = w.RCS(l , n , m , 0);
System.out.println(result);
}