Let's say I have a list [x1, x2, x3] where x1, x2, and x3 can take on any value between 1 and 5.
I want to iterate over every possible list that can be created (From [1, 1, 1], [1, 1, 2], . To [5, 5, 5]). This is an easy problem with only 3 elements in the list.
You can do something like this:
for x = 1; x <= 5; x++;
for y = 1; y <= 5; y++;
...
for q = 1; q <= 5; q++;
create list [x, y, ..., q];
do something with the list;
However, how do you iterate over every possible list where the number of elements is over like 10?
Edi: I've added Java as a constraint. I just want to see how this would be done without too many fancy library calls.
Edit2: What I am really looking for is some algorithm to do this, not what sort of libraries can be used to do it. But what I'm looking for is really a language-independent algorithm.
Using Guava you can do it easily:
public static void main(String[] args) {
int lowerBound = 1;
int upperBound = 5;
int setSize=3;
ContiguousSet<Integer> integers = ContiguousSet.create(Range.closed(lowerBound, upperBound), DiscreteDomain.integers());
List<Set<Integer>> sets = Lists.newArrayList();
for (int i = 0; i < setSize; i++) {
sets.add(integers);
}
Set<List<Integer>> cartesianProduct = Sets.cartesianProduct(sets);
for (List<Integer> list : cartesianProduct) {
System.out.println(list);
}
}
Which prints:
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
[1, 1, 4]
[1, 1, 5]
...
[5, 5, 4]
[5, 5, 5]
Logic :
In arr[x1 x2 x3]; all x1, x2, x3 can have values from 1 to 5. Which means every position in array can have value from 1 to 5. For a value at current position all the values are possible at next position.
suppose at 0 position of array value stored is 1.
[1 _ _] _ represent there is no value.
values for the next position : [1 1 _] , [1 2 _] ,[1 3 _] ,[1 3 _] ,[1 4 _],[1 5 _].
So iterate over current position to store the different possible values from 1 to 5 at current position and for each value call the permutate function again with current position value incremented by 1 for iterating all possible values from 1 to 5 at next position .
Code :
public class permutation {
static int limit;
public static void permutate(int arr[],int curPos)
{
int i;
if(curPos==arr.length)
{
for(i=0;i<arr.length;i++)
{
System.out.print(arr[i] + "\t");
}
System.out.println("");
return;
}
for(i=1;i<=limit;i++)
{
arr[curPos]=i;
permutate(arr,curPos+1);
}
}
public static void main(String[] args) {
int arr[] = new int[3];
limit = 5;
permutate(arr,0);
}
}
Output :
1 1 1
1 1 2
1 1 3
1 1 4
1 1 5
1 2 1
1 2 2
1 2 3
1 2 4
1 2 5
1 3 1
1 3 2
1 3 3
1 3 4
1 3 5
1 4 1
1 4 2
1 4 3
1 4 4
1 4 5
1 5 1
1 5 2
1 5 3
1 5 4
1 5 5
2 1 1
2 1 2
2 1 3
2 1 4
2 1 5
2 2 1
2 2 2
2 2 3
2 2 4
2 2 5
2 3 1
2 3 2
2 3 3
2 3 4
2 3 5
2 4 1
2 4 2
2 4 3
2 4 4
2 4 5
2 5 1
2 5 2
2 5 3
2 5 4
2 5 5
3 1 1
3 1 2
3 1 3
3 1 4
3 1 5
3 2 1
3 2 2
3 2 3
3 2 4
3 2 5
3 3 1
3 3 2
3 3 3
3 3 4
3 3 5
3 4 1
3 4 2
3 4 3
3 4 4
3 4 5
3 5 1
3 5 2
3 5 3
3 5 4
3 5 5
4 1 1
4 1 2
4 1 3
4 1 4
4 1 5
4 2 1
4 2 2
4 2 3
4 2 4
4 2 5
4 3 1
4 3 2
4 3 3
4 3 4
4 3 5
4 4 1
4 4 2
4 4 3
4 4 4
4 4 5
4 5 1
4 5 2
4 5 3
4 5 4
4 5 5
5 1 1
5 1 2
5 1 3
5 1 4
5 1 5
5 2 1
5 2 2
5 2 3
5 2 4
5 2 5
5 3 1
5 3 2
5 3 3
5 3 4
5 3 5
5 4 1
5 4 2
5 4 3
5 4 4
5 4 5
5 5 1
5 5 2
5 5 3
5 5 4
5 5 5
At least in python (You should specify language if it's a constraint):
>>> from itertools import permutations as permu
>>> for i in permu(range(5), 3):
... print i
...
(0, 1, 2)
(0, 1, 3)
(0, 1, 4)
(0, 2, 1)
(0, 2, 3)
(0, 2, 4)
(0, 3, 1)
....
In recursive solution you don't have to sort the list every time. Giving sorted list to recursive function must be sifficient.
To do so, I've written this piece of C# code. Length of output result will be determined by len. Just remember that input length must be equal or bigger than len:
// Input must be sorted, Result must be initialized to empty list
void Iterate(List<int> input, int len, List<int> result)
{
if(result.Count == n)
print result
else
foreach (var i in input)
Iterate(input, len, result.Append(num).ToList())
}
Use this algorithm.
Input: X is the minimum number, Y is the maximum number, and Z is the number of independent choices.
Create an array of size Z, with each element equal to X. Call it Permutation.
Loop:
Add a copy of Permutation to the list of permutations.
Set J to Z minus 1.
Loop:
Add 1 to Permutation[J]. If Permutation[J] is now Y or less, break.
Set Permutation[J] to X.
Subtract 1 from J. If J is now less than 0, return the list of permutations.
Must be classic algorithm. But it always fun to write it from scratch. Here is Java class accepting data set and result list size parameters. Core method is generate(). Also lists might be copied on demand (to be more functional style).
import com.google.common.collect.Maps;
import org.apache.commons.lang.ArrayUtils;
import java.util.Map;
public class PermutationGenerator {
private int listValuesSize;
private int resultListSize;
private String[] currentList;
private Map<String, String> nextValue = Maps.newHashMap();
private int permutations = 0;
public PermutationGenerator(String[] dataSet, int resultListSize) {
this.listValuesSize = dataSet.length;
this.resultListSize = resultListSize;
init(dataSet);
}
private void init(String[] dataSet) {
// rolling values
String previous = dataSet[0];
for (int valuesIndex = 1; valuesIndex < dataSet.length; valuesIndex++) {
nextValue.put(previous, dataSet[valuesIndex]);
previous = dataSet[valuesIndex];
}
nextValue.put(dataSet[dataSet.length - 1], dataSet[0]);
// init
currentList = new String[resultListSize];
for (int i = 0; i < resultListSize; i++) {
currentList[i] = dataSet[0];
}
}
public void generate() {
generate(0, resultListSize - 1);
}
private void generate(int from, int to) {
if (from > to) {
return;
}
for (int i = 0; i < listValuesSize; i++) {
if (from == to) {
processList(currentList);
} else {
generate(from + 1, to);
}
roll(from);
}
}
private void roll(int position) {
currentList[position] = nextValue.get(currentList[position]);
}
private void processList(String[] list) {
permutations++;
System.out.println(ArrayUtils.toString(list));
}
public static void main(String... args) {
PermutationGenerator generator = new PermutationGenerator(new String[]{"1", "2", "3", "4", "5"}, 3);
generator.generate();
System.out.println(generator.permutations);
}
}
Related
I have a string 123456789I also have a bunch of numbers (identities, if you will) such as
2 1 1 1 2 2
2 1 1 1 3 1
2 1 1 2 1 2
2 1 1 2 2 1
2 1 1 3 1 1
The idea is, these numbers specify the groups of digits that should be extracted from the string (left to right order, if that matters). Therefore, a number like 2 3 2 1 1 means Output the first 2 characters, then the next 3 characters, then the next 2 characters, then the next 1 character, then finally the last 1 character remaining.So as examples,2 1 1 1 2 2 should output 12 3 4 5 67 892 1 1 1 3 1 should output 12 3 4 5 678 92 1 1 2 1 2 should output 12 3 4 56 7 892 1 1 2 2 1 should output 12 3 4 56 78 92 1 1 3 1 1 should output 12 3 4 567 8 9
I tried working with the method charAt() but it would seem that's just not for me
public static void main(String[] args) {
String mine = "123456789";
System.out.println(mine.charAt(2)+"\t"+mine.charAt(1)+"\t"+
mine.charAt(1)+"\t"+mine.charAt(1)+"\t"+mine.charAt(2)
+"\t"+mine.charAt(2));
}
The above gives an unwanted output
3 2 2 2 3 3
How do I solve this rather tricky (for me) issue ?
This should do the work for you.
public static void main(String[] args){
String identities = "2 1 1 1 3 1";
String stringToBreakApart = "123456789";
StringBuilder sb = new StringBuilder();
int currentPosition = 0;
for(String identityString : identities.split(" ")){
int identity = Integer.parseInt(identityString);
sb.append(stringToBreakApart, currentPosition, currentPosition += identity);
sb.append(" ");
}
System.out.println(sb.toString());
}
I've given a simple trial on it. Does below give you some help?
public static void main(String[] args) {
int[][] identitiesBunch = new int[][] {
{2, 1, 1, 1, 2, 2},
{2, 1, 1, 1, 3, 1},
{2, 1, 1, 2, 1, 2},
{2, 1, 1, 2, 2, 1},
{2, 1, 1, 3, 1, 1}
};
String mine = "123456789";
char[] numbers = mine.toCharArray();
int index = 0;
for (int[] identities: identitiesBunch) {
for (int id: identities ) {
for (int i = 0 ; i < id; i++)
System.out.print(numbers[index++]);
System.out.print(' ');
}
index = 0;
System.out.println();
}
}
Given an array of positive integers representing terrain heights (in 2-d, ala Super Mario)) and an integer representing a flat sea level, return a container of integers representing the volume of each unique body of water.
Please do not solve the whole problem for me!
I have a few questions:
Lets take an example first.
int [] arr = {4, 3, 5, 6, 4, 2};
int sea_level = 4;
The way it is set up is like this:
6
5 6
4 5 6 4 2
4 3 5 6 4 2
4 3 5 6 4 2
4 3 5 6 4 2
Q So we can't cross over 4 right?
So we have the ranges, [4, 3] and [4, 2] (after the [5, 6] range).
But how do I calculate the volume?
Arraylist<Integer> list = new Arraylist<>();
int volume = 0;
for(int i = 0; i < arr.length; i++){
if(arr[i] <= sea_level){
volume += arr[i];
} else{
list.add(volume); //volume for one block, then reset down.
volume = 0; //loop starts with the next one.
}
}
Is this the way to go about it? I don't understand the problem.
Given your example:
6
5 6 5
4 5 6 5
4 3 5 6 5
4 3 5 6 2 5
4 3 5 6 2 1 5
The water line is at 4, so:
6
5 6 5
~~~~~~~~~~~~5
4 5 6 5
4 3 5 6 5
4 3 5 6 2 5
4 3 5 6 2 1 5
Which makes the water volume the holes beneath the water line, or:
6
5 6 5
~~~~~~~~~~~~5
4 W 5 6 W W 5
4 3 5 6 W W 5
4 3 5 6 2 W 5
4 3 5 6 2 1 5
or, 1 cube of water, and then 5 cubes of water.
Now, how do you calculate that... you need the volume.
The volume is measured between the waterline (4) and the terrain height...
So to measure the volume: sea_level - a[i]
I am trying to implement in Eclipse Java Levenshtein distance on the following two strings:
I took the idea from Wikipedia, but I don't know why my output is wrong, I need help to find my mistake/s.
"kruskal"
"causal"
package il.ac.oranim.alg2016;
public class OPT {
public static void main(String[] args)
{
char[] t={'k','r','u','s','k','a','l'};
char[] s={'c','a','u','s','a','l'};
for (int i=0;i<=s.length;i++)
{
for (int j=0;j<=t.length;j++)
System.out.print(LevenshteinDistance(s,t)[i][j]+" ");
System.out.println();
}
}
private static int[][] LevenshteinDistance(char s[], char t[])
{
// d is a table with m+1 rows and n+1 columns
int[][] d=new int[s.length+1][t.length+1];
for (int i=0;i<=s.length;i++)
d[i][0] = i; // deletion
for (int j=0;j<=t.length;j++)
d[0][j] = j; // insertion
for (int j=1;j<t.length;j++)
{
for (int i=1;i<s.length;i++)
{
if (s[i] ==t[j])
d[i][j]=d[i-1][j-1];
else
d[i][j] = Math.min(Math.min((d[i-1][ j] + 1),
(d[i][j-1] + 1)),
(d[i-1][j-1] + 1)) ;
}
}
return d;
}
}
My output:
0 1 2 3 4 5 6 7
1 1 2 3 4 4 5 0
2 2 1 2 3 4 5 0
3 3 2 1 2 3 4 0
4 4 3 2 2 2 3 0
5 5 4 3 3 3 2 0
6 0 0 0 0 0 0 0
The output should be:
0 1 2 3 4 5 6 7
1 1 2 3 4 5 6 7
2 2 2 3 4 5 5 6
3 3 3 2 3 4 5 6
4 4 4 3 2 3 4 5
5 5 5 4 3 3 3 4
6 6 6 5 4 4 4 3
If you reread the specifications, you will find there are two errors:
on the wikipedia, they use indices ranging from 1 to (and including n), a string starts at index i=1 according to Wikipedia where it is i=0 in Java; and
the weights are not updated correctly:
if (s[i] ==t[j])
d[i][j]=d[i-1][j-1];
In the specifications, this should be the minimum of d[i-1][j]+1, d[i][j-1]+1 and d[i-1][j-1]. It is not guaranteed that d[i-1][j-1] is the lowest value, so you should effectively calculate it.
If one takes these mistakes into account, one can modify the table update algorithm (changes on comment //):
for (int j=1;j<=t.length;j++) { //use <= instead of <
for (int i=1;i<=s.length;i++) { //use <= instead of <
if (s[i-1] ==t[j-1]) //use i-1 and j-1
d[i][j] = Math.min(Math.min(d[i-1][j]+1,d[i][j-1]+1),d[i-1][j-1]); //use the correct update
else
d[i][j] = Math.min(Math.min(d[i-1][j]+1,d[i][j-1]+1),d[i-1][j-1]+1);
}
}
I am writing a Java algorithm which gets each of six players in a game to roll a dice and the highest roll takes the first turn and so on. I have already written the dice rolling method which takes in a map of players in the form of <String playerName, Player player>, and gets each player to roll the dice, where player is a class storing many player attributes necessary for the game.
The problem I am having trouble overcoming when ordering the players is that if two players roll the same number, they then roll again in order to see who goes ahead of the other. Here is an example scenario:
Position: Player (number rolled)
1: Tom (5)
2: Jerry (4)
=3: Jack (3)
=3: Jill (3)
5: Harry (2)
6: Ron (1)
So Jack and Jill roll again. Jack rolls a 6 and Jill rolls a 3. Jack is now in 3rd position and Jill in 4th.
Any strategy I have began to write quickly becomes seemingly overly complicated and very untidy and difficult to read. This is due to having to check if there are any duplicate rolls at any number, all while storing every roll in the correct order, allowing for two or more positions if there is a duplicate roll.
Can anyone come up with a neat structure in which this order can be determined and stored?
Each instance of Player, has a nextPlayer variable that will point to the player in the position after them. It would probably be best to also store numberRolled in the class too. Any players who roll the same number can be stored in a new map and then passed into the rollDice method again.
EDIT
Thanks to Andy Turner, here is my solution:
private Player[] playerOrder = new Player[ModelConstants.NUM_PLAYERS_PLUS_NEUTRALS];
playerOrder = getPlayerOrder();
Player[] getPlayerOrder() {
Player[] players = ModelConstants.PLAYERS.values().toArray(new Player[ModelConstants.PLAYERS.size()]);
String[] playerNames = ModelConstants.PLAYERS.keySet().toArray(new String[ModelConstants.PLAYERS.size()]);
getPlayerOrder(playerNames, players, 0, players.length);
return players;
}
void getPlayerOrder(String[] playerNames, Player[] players, int start, int end) {
// Get all players between players[start] (inclusive) and
// players[end] (exclusive) to re-roll the dice.
for (int i = start; i < end; ++i) {
players[i].setDiceNumberRolled(rollDice(playerNames[i], players[i]));
}
// Sort this portion of the array according to the number rolled.
Arrays.sort(players, start, end, new Comparator<Player>() {
#Override public int compare(Player a, Player b) {
return Integer.compare(a.getDiceNumberRolled(), b.getDiceNumberRolled());
}
});
for (int i = 0; i < playerNames.length; i++) {
playerNames[i] = HashMapUtilities.getKeyFromValue(ModelConstants.PLAYERS, players[i]);
}
// Look for players who rolled the same number.
int i = start;
while (i < end) {
// Try to find a "run" of players with the same number.
int runStart = i;
int diceNumberRolled = players[runStart].getDiceNumberRolled();
i++;
while (i < end && players[i].getDiceNumberRolled() == diceNumberRolled) {
i++;
}
if (i - runStart > 1) {
// We have found more than one player with the same dice number.
// Get all of the players with that dice number to roll again.
addMessageToLog(MessageType.INFO, "There has been a tie." , 2000);
tiedPlayers = true;
getPlayerOrder(playerNames, players, runStart, i);
tiedPlayers = false;
}
}
}
private int rollDice(String playerName, Player player) {
int numberRolled = 0;
if (player.getPlayerType().equals(PlayerType.HUMAN)) {
boolean diceRolled = false;
while (!diceRolled) {
String message = ", roll the dice";
if (tiedPlayers == true) {
message += " again.";
}
else {
message += ".";
}
String userInput = getCommand(playerName + message, "Invlaid command. Type \"Roll Dice\" or something similar.", 2000);
if (userInput.equalsIgnoreCase("Roll Dice") || userInput.equalsIgnoreCase("roll the dice") || userInput.equalsIgnoreCase("Roll")) {
numberRolled = dice.rollDice();
diceRolled = true;
}
else {
addMessageToLog(MessageType.ERROR, "Invlaid command. Type \"Roll Dice\" or something similar.", 0);
}
}
}
else {
String message = " is now rolling the dice";
if (tiedPlayers == true) {
message += " again...";
}
else {
message += "...";
}
addMessageToLog(MessageType.INFO, playerName + message, 2000);
numberRolled = dice.rollDice();
}
player.setDiceNumberRolled(numberRolled);
addMessageToLog(MessageType.SUCCESS, playerName + " rolled a " + numberRolled, 1000);
addDicePanel(numberRolled);
return numberRolled;
}
private void setPlayerOrder() {
for (int i = 0; i < playerOrder.length; i++) {
if (i == (playerOrder.length - 1)) {
playerOrder[i].setNextPlayer(playerOrder[0]);
}
else {
playerOrder[i].setNextPlayer(playerOrder[i + 1]);
}
}
activePlayer = playerOrder[0];
}
private void changePlayer() {
activePlayer = activePlayer.getNextPlayer();
}
There are 2 ways to deal with this.
1) The simple thing is to forget the "dice-roll". Generate 32 random (one int) bits for each player and use that for ordering. If they happen to match pick whatever player you want. It's going to be so rare that it doesn't really matter (1 in 4 billion that you get 2 numbers to be the same).
2) If you want to stick to dice-roll. Create a function that takes a list of players, rolls the dice internally and returns the correctly ordered one. Whenever you have equal rolls call create a smaller list with the players that are equals and call the function recursively to give you the ordering of those players. When it returns copy it in the result and continue. You can prove mathematically that it's highly unlikely(read impossible) that this will result in an infinite loop.
To organize stuff, try to create a separate method for each "action" you need - one method for rolling the dice, another to find duplicates, and another to sort. here are the steps:
Roll dice for all players, store in a List
Find duplicates
For all duplicates, repeat step 1 and 2 until no duplicates are found.
Sort the players.
3 methods. 4 steps. logically executed to do what you need.
public int rolldice(Player player);
public List<Player> findDuplicates (List<Player> players);
public void sortPlayers(List<Player> players);
you can already work with these 3 methods. Hope this helps
You can put all of the players into an array - the order of the players in an array can be used to indicate the order of play.
Get them all to pick a dice roll; then sort them by the number they rolled (using a custom comparator).
Now, look for 2 or more players that rolled the same number - these are next to each other because the array is sorted. Now, you can recursively call the same logic to get just those players to re-roll, but only on the portion of the array where those players had the same dice roll.
For example:
Player[] getPlayerOrder() {
Player[] players = playerMap.values().toArray(new Player[playerMap.size()]);
getPlayerOrder(players, 0, players.length);
return players;
}
void getPlayerOrder(Player[] players, int start, int end) {
// Get all players between players[start] (inclusive) and
// players[end] (exclusive) to re-roll the dice.
for (int i = start; i < end; ++i) {
// Logic to roll dice...
players[i].setDiceNumberRolled(...);
}
// Sort this portion of the array according to the number rolled.
Arrays.sort(players, start, end, new Comparator<Player>() {
#Override public int compare(Player a, Player b) {
return Integer.compare(b.getDiceNumberRolled(), a.getDiceNumberRolled());
}
});
// Look for players who rolled the same number.
int i = start;
while (i < end) {
// Try to find a "run" of players with the same number.
int runStart = i;
int diceNumberRolled = players[runStart].getDiceNumberRolled();
++i;
while (i < end && players[i].getDiceNumberRolled() == diceNumberRolled) {
++i;
}
if (i - runStart > 1) {
// We have found more than one player with the same dice number.
// Get all of the players with that dice number to roll again.
getPlayerOrder(players, runStart, i);
}
}
}
My attemp would be to let everyone roll the dice and just store it without any sort. Then check for duplicates and let the players who got the same numbers roll again. Afterwards when every Player rolled and nothig duplicate anymore just use some Sort Algorithm. Simplest one for that would be BubbleSort since you have no time issue when sorting. Check out this enter link description here
The iterative solution not as simple as I first thought!
I originally posted a solution using primitive int arrays for players & dice.
But this was needlessly complex to code. Easier by far to use composite class, PlayerDice. An array of such objects can be sorted using Arrays.sort(...) method for desired range of the array according to the compareTo(.) method defined for PlayerDice.
You have to be careful to store the end index when some of a group of players tied on the same dice again tie after a roll-off. These I put into a stack - except where the entire group of tied players throw the same dice on a roll-off.
The overall finish condition is when there are no ties and the start-index is greater than the end-index.
package snakesAndLadders;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Stack;
public class PlayOrderTest6
{
private final static int numPlayers = 16;
private PlayerDice[] playersDice = new PlayerDice[numPlayers];
/** Composite class to enable sorting of players according to dice they throw.*/
public static class PlayerDice implements Comparable<PlayerDice>
{
private int player;
private int dice;
public PlayerDice(int player, int dice)
{
this.player = player;
this.dice = dice;
}
public int getPlayer()
{
return player;
}
public void setPlayer(int player)
{
this.player = player;
}
public int getDice()
{
return dice;
}
public void setDice(int dice)
{
this.dice = dice;
}
public String toString()
{
return "Player# " + player + " | Dice: " + dice;
}
#Override
public int compareTo(PlayerDice pd)
{
// Default comparison is on basis of dice value descending:
return pd.getDice() - this.dice;
}
}
/** Main method basically runs the getPlayOrder(.) method for the number of
players involved in this game, i.e. the attribute players. */
public static void main(String[] args)
{
int[] playOrder = new int[numPlayers]; // Holds final play order
// Initialize playerDice array and give each player a number between 1 .. players :
for(int i = 0; i < numPlayers; i++)
{
playersDice[i] = new PlayerDice(i + 1, 1);
playOrder[i] = i + 1;
}
// Generate the order of play by rolling dice & re-rolling for tied players :
getPlayOrder(playersDice);
// Extract play order :
for(int i = 0; i < numPlayers; i++)
playOrder[i] = playersDice[i].getPlayer();
System.out.println("\n\nFinal Player Order is : " + Arrays.toString(playOrder));
}
public static void getPlayOrder(PlayerDice[] p)
{
int start = 0, // Start index of unsorted PlayerDice array
end = numPlayers - 1; // End index of unsorted PlayerDice array
Integer[] sdInds = new Integer[2]; // For start & end indices of first group of tied players.
Stack<Integer> endStack = new Stack<Integer>(); // Holds end index when a dice-roll to sort a tie produces another tie.
while (start < numPlayers && end > start)
{
// Roll dice for players in index range between start & end :
for(int i = start; i < end + 1; i++)
p[i].setDice( (int) (6 * Math.random() + 1));
// Output player/dice values :
System.out.print("\n\nPlayer Order:\t\t");
for(int i = 0; i < numPlayers; i++)
System.out.print(p[i].getPlayer() + "\t");
System.out.print("\nDice Rolled:\t\t");
for(int i = 0; i < numPlayers; i++)
System.out.print(p[i].getDice() + "\t");
// Sort players between start & end indices by their dice number descending :
Arrays.sort(p, start, end + 1); // Uses PlayerDice compareTo(.) method, i.e. by dice value descending.
// Output player/dice values :
System.out.print("\n\nSorted Player Order:\t");
for(int i = 0; i < numPlayers; i++)
System.out.print(p[i].getPlayer() + "\t");
System.out.print("\nSorted Dice Rolled:\t");
for(int i = 0; i < numPlayers; i++)
System.out.print(p[i].getDice() + "\t");
// Find first group of players (from leftmost element of p) on the same dice :
sdInds[0] = -1;
sdInds[1] = -1;
findTiedPlayers(p, start, end, sdInds);
System.out.print("\nsdInds[0]: " + sdInds[0]);
System.out.print("\nsdInds[1]: " + sdInds[1]);
// Where tied players are found ...
if (sdInds[0] != -1)
{ // Re-set start and end indices and re-roll dice to sort the tied group :
start = sdInds[0];
if (sdInds[1] != end)
{
endStack.push(end); // Keeps priority of tied players over those on lower first dice roll
end = sdInds[1];
}
}
else // Where no ties, reset start & end indices till ties found or all players sorted.
while (sdInds[0] == -1 && end >= start)
{
start = end + 1;
if(!endStack.isEmpty())
end = endStack.pop();
else
break; // When no more players to be checked !
// Get indices of first tied group in remaining players :
sdInds[0] = -1; // Initializing start- ...
sdInds[1] = -1; // ... and end-indices before tie search.
findTiedPlayers(p, start, end, sdInds);
if (sdInds[0]!= -1) // If ties found, adjust start & end indices before tie-breaker roll
{
start = sdInds[0];
endStack.push(end); // Store old end index
end = sdInds[1];
}
}
System.out.print("\nstart: " + start);
System.out.print("\nend: " + end);
}
}
/** Method to find first group of tied players in an array holding player & dice data.
* #param pt - a PlayerDice array;
* #param st - an int holding the start index of the range of pt being examined;
* #param en - an int holding the end index of the range of pt being examined;
* #param tInds - an int array holding the start & end index of the
first group of tied players.
This parameter also acts as a return parameter since it's a reference type,
tInds[0] holding the index of the first tied player and tInds[1] the index of
the last. Where no ties are found, both tInds elements retain their received
values of -1 which signifies no ties. */
public static void findTiedPlayers(PlayerDice[] pt, int st, int en, Integer[] tInds)
{
for(int i = st; i < en; i++)
{
for(int j = i + 1; j < en + 1; j++)
if (pt[i].getDice() == pt[j].getDice())
{
tInds[0] = i;
tInds[1] = j;
}
if (tInds[0] != -1) // First group of tied players found ...
break; // ... finish search !
}
}
}
OUTPUT:
Player Order: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Dice Rolled: 4 4 6 5 2 1 3 6 1 3 4 4 1 2 1 3
Sorted Player Order: 3 8 4 1 2 11 12 7 10 16 5 14 6 9 13 15
Sorted Dice Rolled: 6 6 5 4 4 4 4 3 3 3 2 2 1 1 1 1
sdInds[0]: 0
sdInds[1]: 1
start: 0
end: 1
Player Order: 3 8 4 1 2 11 12 7 10 16 5 14 6 9 13 15
Dice Rolled: 5 6 5 4 4 4 4 3 3 3 2 2 1 1 1 1
Sorted Player Order: 8 3 4 1 2 11 12 7 10 16 5 14 6 9 13 15
Sorted Dice Rolled: 6 5 5 4 4 4 4 3 3 3 2 2 1 1 1 1
sdInds[0]: -1
sdInds[1]: -1
start: 3
end: 6
Player Order: 8 3 4 1 2 11 12 7 10 16 5 14 6 9 13 15
Dice Rolled: 6 5 5 2 6 1 1 3 3 3 2 2 1 1 1 1
Sorted Player Order: 8 3 4 2 1 11 12 7 10 16 5 14 6 9 13 15
Sorted Dice Rolled: 6 5 5 6 2 1 1 3 3 3 2 2 1 1 1 1
sdInds[0]: 5
sdInds[1]: 6
start: 5
end: 6
Player Order: 8 3 4 2 1 11 12 7 10 16 5 14 6 9 13 15
Dice Rolled: 6 5 5 6 2 4 4 3 3 3 2 2 1 1 1 1
Sorted Player Order: 8 3 4 2 1 11 12 7 10 16 5 14 6 9 13 15
Sorted Dice Rolled: 6 5 5 6 2 4 4 3 3 3 2 2 1 1 1 1
sdInds[0]: 5
sdInds[1]: 6
start: 5
end: 6
Player Order: 8 3 4 2 1 11 12 7 10 16 5 14 6 9 13 15
Dice Rolled: 6 5 5 6 2 5 1 3 3 3 2 2 1 1 1 1
Sorted Player Order: 8 3 4 2 1 11 12 7 10 16 5 14 6 9 13 15
Sorted Dice Rolled: 6 5 5 6 2 5 1 3 3 3 2 2 1 1 1 1
sdInds[0]: -1
sdInds[1]: -1
start: 7
end: 9
Player Order: 8 3 4 2 1 11 12 7 10 16 5 14 6 9 13 15
Dice Rolled: 6 5 5 6 2 5 1 2 6 3 2 2 1 1 1 1
Sorted Player Order: 8 3 4 2 1 11 12 10 16 7 5 14 6 9 13 15
Sorted Dice Rolled: 6 5 5 6 2 5 1 6 3 2 2 2 1 1 1 1
sdInds[0]: -1
sdInds[1]: -1
start: 10
end: 11
Player Order: 8 3 4 2 1 11 12 10 16 7 5 14 6 9 13 15
Dice Rolled: 6 5 5 6 2 5 1 6 3 2 4 6 1 1 1 1
Sorted Player Order: 8 3 4 2 1 11 12 10 16 7 14 5 6 9 13 15
Sorted Dice Rolled: 6 5 5 6 2 5 1 6 3 2 6 4 1 1 1 1
sdInds[0]: -1
sdInds[1]: -1
start: 12
end: 15
Player Order: 8 3 4 2 1 11 12 10 16 7 14 5 6 9 13 15
Dice Rolled: 6 5 5 6 2 5 1 6 3 2 6 4 5 4 5 5
Sorted Player Order: 8 3 4 2 1 11 12 10 16 7 14 5 6 13 15 9
Sorted Dice Rolled: 6 5 5 6 2 5 1 6 3 2 6 4 5 5 5 4
sdInds[0]: 12
sdInds[1]: 14
start: 12
end: 14
Player Order: 8 3 4 2 1 11 12 10 16 7 14 5 6 13 15 9
Dice Rolled: 6 5 5 6 2 5 1 6 3 2 6 4 6 2 5 4
Sorted Player Order: 8 3 4 2 1 11 12 10 16 7 14 5 6 15 13 9
Sorted Dice Rolled: 6 5 5 6 2 5 1 6 3 2 6 4 6 5 2 4
sdInds[0]: -1
sdInds[1]: -1
start: 16
end: 15
Final Player Order is : [8, 3, 4, 2, 1, 11, 12, 10, 16, 7, 14, 5, 6, 15, 13, 9]
I'm trying to split the array into odd and even numbers. Note that sorting numbers in the final result does not matter. I'm compiling the code and the output contains some bug. My code arranges odd numbers correctly while the even numbers are giving me some trouble. Could somebody please help me out with the arrangement of even numbers?
Basically, I arrange odd numbers in the left side of the array and have oddPos = 0 in the beginning; even numbers are in the right side and the positioning starts from the very end of the array evenPos = myArray.length - 1.
public class EvenOddArray {
public static void main(String[] args){
int[] myArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int oddPos = 0;
int evenPos = myArray.length - 1;
for(int i = 0; i < myArray.length; i++){
if(myArray[i] % 2 == 0){
myArray[evenPos] = myArray[i];
evenPos--;
}
else{
myArray[oddPos] = myArray[i];
oddPos++;
}
}
for(int i = 0; i < myArray.length; i++){
System.out.print(myArray[i] + " ");
}
}
}
Output:
1 3 5 7 2 4 6 6 4 2
int current = 0;
int evenPos = myArray.Length - 1;
while (current < evenPos) {
if (myArray[current] % 2 == 0) {
swap(myArray, evenPos, current);
evenPos--;
} else {
current++;
}
}
A squeezed funny version:
for (int curPos=0, evenPos=myArray.length-1; curPos < evenPos;)
if (myArray[curPos] % 2 == 0)
swap(myArray, evenPos--, curPos);
else
curPos++;
More fun version:
for (int curPos=0, evenPos=myArray.length-1; curPos < evenPos;)
swap(myArray, curPos, myArray[curPos]%2==0 ? evenPos-- : curPos++);
explanation:
You don't have to swap values when the number is odd. you only
increase the current counter.
you can't use the for loop counter as an index to the array too. to
not miss the numbers that gets swapped to the counter index not
processed. this is the mistake that other answers didn't cover.
Actually you are editing the same myArray array while reading from it. So what happens is,
You insert 6 into the myArray[7] th position, in the 6th iteration of the loop. So, during the 7th iteration when you read the myArray[7], it is 6. Not 8. Because, you have over written 8 with 6 in the previous iteration.
Therefore, use a separate array to hold the results. Hope you get the point.
You can do something like this,
int[] myArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] resultArray = new int[myArray.length];
int oddPos = 0;
int evenPos = myArray.length - 1;
for(int i = 0; i < myArray.length; i++){
if(myArray[i] % 2 == 0){
resultArray[evenPos] = myArray[i];
evenPos--;
}
else{
resultArray[oddPos] = myArray[i];
oddPos++;
}
}
Lets see what happens with each Iteration of your for loop.
Original: 1 2 3 4 5 6 7 8 9 10
1st Iter: 1 2 3 4 5 6 7 8 9 10
2nd Iter: 1 2 3 4 5 6 7 8 9 2
3rd Iter: 1 3 3 4 5 6 7 8 9 2
4th Iter: 1 3 3 4 5 6 7 8 4 2
5th Iter: 1 3 5 4 5 6 7 8 4 2
6th Iter: 1 3 5 4 5 6 7 6 4 2
7th Iter: 1 3 5 7 5 6 7 6 4 2
8th Iter: 1 3 5 7 5 6 6 6 4 2
9th Iter: 1 3 5 7 5 4 6 6 4 2
10th Iter: 1 3 5 7 2 4 6 6 4 2
As you can see, you are modifying the array "inplace". You are modifying the array without using all the values. For example, look at 9, It gets over written before it is ever accessed. So, your algo is wrong.
Suggestions:
Use a new array to hold the results as in tibzon's answer
Use swapping instead of overwriting. You have to update your algo accordingly. I was going to provide one. But Murenik already provided one.
Here is my optimized version, which uses around half of the swaps compared to the #hasan83 version.
int n = myArray.length;
int oddPos = 0;
int evenPos = n - 1;
while (true) {
while (oddPos < n && myArray[oddPos] % 2 == 1) {
oddPos++;
}
while (evenPos >= 0 && myArray[evenPos] % 2 == 0) {
evenPos--;
}
if (oddPos >= evenPos) break;
swap(myArray, oddPos, evenPos);
}