I'm trying to get a printout of all variations of a certain String. For example, we have this input: AB0C0. The 0 in the 3rd and 5th spots should be treated as variables. The variable characters are 1, 2, and 3 to be placed in the spot of 0. This means there would be all possible variations of this input:
AB1C1
AB2C1
AB3C1
AB1C2
AB1C3
AB2C2
AB2C3
AB3C2
AB3C3
This is just an example. A 5-character long string is a place for 1 to 5 variables. The issue I'm facing is, that it should generate all variations no matter how many variables are in the input in no matter in which place they are.
Scanner scanner = new Scanner (System.in);
System.out.println("Enter the key consisting of 5 characters:");
String input = scanner.next();
String strOutput1 = input.replaceFirst("0","1");
String strOutput1A = input.replace("0","1");
String strOutput2 = input.replaceFirst("0","2");
String strOutput3 = input.replaceFirst("0","3");
String strOutput4 = input.replaceFirst("0","4");
String strOutput5 = input.replaceFirst("0","5");
System.out.println(strOutput1.toUpperCase());
System.out.println(strOutput1A.toUpperCase());
System.out.println(strOutput2.toUpperCase());
System.out.println(strOutput3.toUpperCase());
System.out.println(strOutput4.toUpperCase());
System.out.println(strOutput5.toUpperCase());
What about this:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the key consisting of 5 characters:");
String input = scanner.next();
//find positions of '0' in input
List<Integer> varPositions = findVarPositions(input);
//create permutations
List<String> permutations = new ArrayList<>();
permutations.add(input);//AB0C0
for (int position : varPositions) {
permutations = permutateAtPosition(permutations, position);
}
//print permutations
for (String permutation : permutations) {
System.out.println(permutation.toUpperCase());
}
}
private static List<Integer> findVarPositions(String input) {
List<Integer> varPositions = new ArrayList<>();
int lastVarPosition = -1;
while ((lastVarPosition = input.indexOf('0', lastVarPosition + 1)) != -1) {
varPositions.add(lastVarPosition);
}
return varPositions;
}
private static List<String> permutateAtPosition(List<String> partialyPermutated, int position) {
List<String> result = new ArrayList<>();
char[] replacements = {'1', '2', '3', '4', '5'};
for (String item : partialyPermutated) {
for (int i = 0; i < replacements.length; i++) {
String output = replaceCharAt(item, position, replacements[i]);
result.add(output);
}
}
return result;
}
private static String replaceCharAt(String input, int position, char replacement) {
//converting to char array, because there's no method like
//String.replaceAtPosition(position, char)
char[] charArray = input.toCharArray();
charArray[position] = replacement;
return new String(charArray);
}
}
It's not fixed to a number of variables.
The idea is to extract positions of '0' and subsequently call the method permutateAtPosition, which takes a partially permutated list and permutates it by one more level.
For "a0b0c0" and values 1-2 it would be ['a0b0c0'], then ['a1b0c0','a2b0c0'], then ['a1b1c0','a1b2c0','a2b1c0','a2b2c0'], and finally ['a1b1c1','a1b1c2','a1b2c1','a1b2c2','a2b1c1','a2b1c2','a2b2c1''a2b2c2'].
This solution keeps everything in memory, so in the general case (unlimited input string) it would be wiser to go with depth-first instead.
I've got another solution for you.
First step, getting the amount of variables:
int variableCount = 0;
for (int i = 0; i < 5; i++) {
if (input.charAt(i) == '0') {
variableCount++;
}
}
Then calculating the amount of results we are expecting:
int countMax = (int)Math.pow(4,variableCount);
Lastly, count up in base 4. Pad the number with 0's and replace the original input 0's:
for (int i = 0; i < countMax; i++) {
String paddedNumbers = format("%" + variableCount + "s",Integer.toString(i, 4)).replace(" ", "0");
int replacedCount = 0;
char[] outputChars = input.toCharArray();
for (int j = 0; j < 5; j++) {
if (input.charAt(j) == '0') {
outputChars[j] = paddedNumbers.charAt(replacedCount);
replacedCount++;
}
}
System.out.println(outputChars);
}
Related
The task is to write the logic of checking the magnitude of the coincidence of the player's attempt with the hidden word.
More formally, let there be a string S — a hidden word and a string Q — a player's attempt.
Both strings have the same length N. For each position 1 ≤ i ≤ N of string Q, we need to calculate the type of match in this position with string S.
If Q[i] = S[i], then at position i the match type should be equal to "correct".
If Q[i]≠S[i], but there is another position 1 ≤ j≤ N such that Q[i] = S[j], then in position i the match type must be equal to "present".
Each letter of the string S can be used in no more than one match of
the type "correct" or "present".
Priority is always given to the "correct" type.
Of all possible use cases in the "present" type, the program selects
the leftmost position in the Q string.
In other positions, the match type must be equal to "absent".
Input format:
The first line contains the string S (1≤ S ≤ 10^6) — the hidden word.
The second line contains the string Q ( Q = S) — the player's attempt.
It is guaranteed that the strings S and Q contain only uppercase Latin letters.
Example:
input:
COVER
CLEAR
output:
correct
absent
present
absent
correct
My program does this very slowly, how can I speed it up?
import java.util.*;
public class Task1 {
private final static String cor = "correct";
private final static String abs = "absent";
private final static String pre = "present";
static String[] stringArr;
static java.util.Map<Integer, Integer> map = new HashMap<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a = sc.nextLine();
String b = sc.nextLine();
stringArr = new String[a.length()];
int length1 = a.length();
char[] arr1 = a.toCharArray();
char[] arr2 = b.toCharArray();
for (int i = 0; i < length1; i++) {
if (arr2[i] == arr1[i]) {
stringArr[i] = cor;
map.put(i, i);
}
}
for (int i = 0; i < length1; i++) {
if (arr2[i] != arr1[i]) {
while (stringArr[i] == null) {
boolean finded = false;
for (int j = 0; j < arr1.length; j++) {
if (arr2[i] == arr1[j] && !map.containsKey(j)) {
stringArr[i] = pre;
finded = true;
map.put(j, j);
break;
}
}
if (!finded) stringArr[i] = abs;
}
}
}
for (String s : stringArr) {
System.out.println(s);
}
}
}
You can use an int array (or a HashMap<Char, Integer>) count to store those "presented" characters.
We need two for loops. The first loop will set all "correct" positions (if arr1[i] == arr2[i], then stringArr[i] = cor); and for those unmatched positions (arr1[i] != arr2[i]), we count the number of occurrences for those characters in the hidden word (count[arr1[i] - 'A']++).
Then in the second for loop, we check those unmatched positions with the help of count.
If count[arr2[i] - 'A'] > 0, it means that the hidden word contains the character arr2[i], so we can set stringArr[i] = pre and decrement count[arr2[i] - 'A'] (since each letter can be used once)
Otherwise, there's no matching letter in the hidden word, stringArr[i] should be set to abs.
import java.util.Scanner;
public class Task1 {
private final static String cor = "correct";
private final static String abs = "absent";
private final static String pre = "present";
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String a = sc.nextLine();
String b = sc.nextLine();
String[] stringArr = new String[a.length()];
int length1 = a.length();
char[] arr1 = a.toCharArray();
char[] arr2 = b.toCharArray();
int[] count = new int[26];
for (int i = 0; i < length1; i++) {
if (arr2[i] == arr1[i]) {
stringArr[i] = cor;
}
else {
count[arr1[i] - 'A']++;
}
}
for (int i = 0; i < length1; i++) {
if (arr1[i] != arr2[i]) {
if (count[arr2[i] - 'A'] > 0) {
stringArr[i] = pre;
count[arr2[i] - 'A']--;
}
else {
stringArr[i] = abs;
}
}
}
for (String s : stringArr) {
System.out.println(s);
}
}
}
This can be done using hashmaps and taking advantage of the o(1) insert/delete time.
I'm assuming that each word is exactly the same length. Consequently, to get the answer, we need to check each letter in each word. If they have a length of n, then that means at a minimum it will take o(2n) == o(n) to find the answer.
[1] Then, if you're able to use extra space, I would just use a hashmap as an index, where the key is a character in secret, and the value is the set of indices that letter occurs in secret. So it would look something like this:
//cover
c:<0>
o:<1>
etx...
[2] Then check each letter in guess against the index.
If there is no key for a letter, the put absent
If there is a key, then look in the set of indices to see if there is a matching index. Since I used a hashset, that's another o(1) lookup
So sum total, you walk through secret and guess once each which is o(n) runtime. That, plus o(1) for each index lookup produces o(n) runtime.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class Task1 {
public static void main(String[] args)
{
ArrayList<String> res = solve("COVER", "CLEAR");
System.out.println(res);
}
public static ArrayList<String> solve(String secret, String guess){
ArrayList<String> result = new ArrayList<>();
HashMap<Character, HashSet<Integer>> index = new HashMap<>();
//shortcut
if(secret.equals(guess)){
for(int i = 0; i < secret.length(); i++) result.add("correct");
return result;
}
//make the index of char:<indices> for the chars in "secret"
for(int i = 0; i < secret.length(); i++){
char c = secret.charAt(i);
HashSet<Integer> bucket = index.get(c);
if(bucket == null){
bucket = new HashSet<>();
index.put(c, bucket);
}
bucket.add(i);
}
//check each char in "guess" against the index and tally the result
for(int i = 0; i < guess.length(); i++){
char c = guess.charAt(i);
HashSet<Integer> bucket = index.get(c);
if(bucket == null) result.add("absent");
else if(bucket.contains(i)) result.add("correct");
else result.add("present");
}
return result;
}
}
I am trying to create a program that outputs ten lowercase letter characters - five vowels and five consonants. In order to do this, I have started by creating a char array with a range between 'a' and 'z' called letters[] with size 10. Once the array is filled, I will print the output with the use of a format string containing everything in the array.
My question is, how would I make the program output exactly five of each type (and keep the order of the characters printed completely random)? I have considered using the switch statement with a case each for consonants and vowels, but my ideas so far seem over-complicated and inelegant.
Code so far:
char letters[] = new char[10];
for(int i = 0; i < letters.length; i++){ //Open for
letters[i] = (char)(97 + Math.random() * 26);
char idx = letters[i];
System.out.printf("%s",idx);
} //End for
If you don't mind a somewhat more String-related solution, here is one. I am assuming that you don't want any consonant or vowel repeated in the output string, so this algorithm removes letters for consideration once they've been used. It also provides a bit more of a generic letter picker routine that's not really limited to vowels and consonants.
import java.lang.StringBuilder;
public class Shuffler {
public static String CONSONANTS = "bcdfghjklmnpqrstvwxyz";
public static String VOWELS = "aeiou";
/*
* Returns a new string that is a combination of the current string and 'count'
* characters from the source string (using any character in the source string
* no more than one time).
*/
public static String shuffleIntoString(String current, String source, int count) {
if (current == null || source == null || count < 0 || count > source.length()) {
System.out.println("Error in parameters to shuffleIntoString");
return null;
}
StringBuilder retval = new StringBuilder(current); // build up by inserting at random locations
StringBuilder depletedSource = new StringBuilder(source); // remove characters as they are used
for (int i = 0; i < count; i++) {
int pick = (int) (Math.random() * depletedSource.length());
int whereToInsert = (int) (Math.random() * retval.length());
retval = retval.insert(whereToInsert, depletedSource.charAt(pick));
depletedSource.deleteCharAt(pick);
}
return retval.toString();
}
public static void main(String[] args) {
Shuffler shuf = new Shuffler();
for (int i = 0; i < 10; i++) {
String result = shuf.shuffleIntoString("", shuf.CONSONANTS, 5);
result = shuf.shuffleIntoString(result, shuf.VOWELS, 5);
System.out.println(result);
}
}
}
And the output looks like this:
kqoibauzed
uhcawoerib
afdzoemius
yuagocibej
eiuhaokcyq
ouveiawrxn
uyaiveomxn
ruxeoalhij
uraliwfeoc
afoutiesmr
This will achieve what you desire if you are content with using ArrayLists. To generate the random chars you could generate a number within the index of the corresponding char Strings and add the value to the ArrayList. Collections is a helpful Class that you can use to shuffle the list.
List<Character> list = new ArrayList<>();
String consonants = "bcdfghjklmnpqrstvwxyz";
String vowels = "aeiou";
Random r = new Random();
for (int i = 0; i < 5; i++) {
list.add(consonants.charAt(r.nextInt(consonants.length()))); // Add consonant
list.add(vowels.charAt(r.nextInt(vowels.length()))); // Add vowel
}
Collections.shuffle(list);
for (Character c : list) {
System.out.println(c);
}
I don't seen any rules about duplicated but if you want you can remove latters from arrays after selection.
List<Character> vowels = Arrays.asList('a', 'e', 'i', 'o', 'u');
List<Character> consonants = new ArrayList<>();
for (char latter = 'a'; latter <= 'z'; latter++) {
if(!vowels.contains(latter)) {
consonants.add(latter);
}
}
final Random random = new Random();
int vowelsRemain = 5;
int consonantsRemain = 5;
List<Character> result = new ArrayList<>();
while (vowelsRemain > 0 && consonantsRemain > 0) {
final boolean generateVowel = random.nextBoolean();
final char randomLatter;
if(generateVowel) {
randomLatter = vowels.get(random.nextInt(vowels.size()));
vowelsRemain--;
} else {
randomLatter = consonants.get(random.nextInt(consonants.size()));
consonantsRemain--;
}
result.add(randomLatter);
}
while (vowelsRemain > 0) {
final Character randomVowel = vowels.get(random.nextInt(vowels.size()));
result.add(randomVowel);
vowelsRemain--;
}
while (consonantsRemain > 0) {
final Character randomConsonant = consonants.get(random.nextInt(consonants.size()));
result.add(randomConsonant);
consonantsRemain--;
}
System.out.println(result);
EDIT: right, I forgot to state the problem -- which is the fact that I get 0 as an output.
CONTEXT
My program aims to take a user-inputted number-word (1- 99) and output it as an integer (i.e. thirty-four = 34). I can't figure out where the error in my code is and need help:
Scanner scInput = new Scanner(System.in);
String word = scInput.nextLine(); //number in word-form (i.e. twenty six)
char[] charArray = word.toCharArray();//string to char array for word^
int divider = 0; //position of hyphen/space in charArray
All 2-word numbers are comprised of a tens value & a ones value. Assuming proper syntax [english], the word before the hyphen/space divider is the tens and the word following divider is the ones.
ARRAYS
//word values - components & syntax (1-99)
//ONES
public static final String[] wONES = {"one","two","three","four","five","six","seven","eight","nine"};
//TENS
public static final String[] wTENS = {null,"twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"};
//TEENS
public static final String[] wTEENS = {"ten", "eleven", "twelve", "thirteen","fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
I've organized all the word-components into 3 different arrays: ones, tens, and teens.
//equivalent integer-array of above String arrays
//ONES
public static final int[] nONES = {1,2,3,4,5,6,7,8,9};
//TENS
public static final int[] nTENS = {0,20,30,40,50,60,70,80,90};
//TEENS
public static final int[] nTEENS = {10,11,12,13,14,15,16,17,18,19};
I created 3 other arrays that are the same as the above three arrays, except they store the integer values.
CODE
Here I separate the user-inputted String into two sections: the tens and the ones. So if the number was 72: 70 = tens and 2 = ones.
int tensValue = 0; //number's tens value (i.e. 30)
int onesValue = 0; //ones value (i.e. 3)
char[] tensArray = null; //array storing tens section of word (before divider)
for (int u = 0; u < divider; u++){
tensArray[u] = charArray[u];
}
String tens = new String(tensArray); //convert char array to String
char[] onesArray = null; //array storing ones section of word (after divider)
for (int u = divider + 1; u > divider && u < charArray.length; u++){
onesArray[u] = charArray[u];
}
String ones = new String(onesArray);
//searches for matches in String array for tens
for(int u = 0; u < wTENS.length; u++){
if(tens.equals(wTENS[u])){
tensValue = nTENS[u];
total += tensValue;
}
}
//searches for matches in String array for ones
for(int u = 0; u < wONES.length; u++){
if(ones.equals(wONES[u])){
onesValue = nONES[u];
total += onesValue;
In your current code you are doing char[] tensArray = null; which should be something like char[] tensArray = new char[10]; or else you end up with NPE.
It might not be most efficient but here is a simple and better approach to your problem.
Read the line and split it on white space (assuming you are separating your words by a space).
Search each of the tokens you get after split in the above lists and add the corresponding number (same index) to your answer.
Print the answer.
Here is the code snippet:
class Main
{
public static final String[] wONES = {"one","two","three","four","five","six",
"seven","eight","nine"};
public static final String[] wTENS = {"ten","twenty","thirty","forty","fifty","sixty",
"seventy","eighty","ninety"};
public static final String[] wTEENS = {"eleven", "twelve", "thirteen","fourteen",
"fifteen", "sixteen", "seventeen", "eighteen",
"nineteen"};
public static final int[] nONES = {1,2,3,4,5,6,7,8,9};
public static final int[] nTENS = {10,20,30,40,50,60,70,80,90};
public static final int[] nTEENS = {11,12,13,14,15,16,17,18,19};
public static void main (String[] args) throws Exception
{
Scanner scInput = new Scanner(System.in);
String word = scInput.nextLine();
int answer = 0;
/* Assuming you are giving space between words */
for(String s : word.split(" ")) {
/* Scan wONES */
for(int i = 0; i < wONES.length; i++) {
if(wONES[i].equalsIgnoreCase(s)) {
answer += nONES[i];
continue;
}
}
/* Scan wTENS */
for(int i = 0; i < wTENS.length; i++) {
if(wTENS[i].equalsIgnoreCase(s)) {
answer += nTENS[i];
continue;
}
}
/* Scan wTEENS */
for(int i = 0; i < wTEENS.length; i++) {
if(wTEENS[i].equalsIgnoreCase(s)) {
answer += nTEENS[i];
continue;
}
}
}
System.out.println("Result: " + answer);
}
}
Input:
thirty four
Output:
34
You have an interesting approach to this problem. A couple of things to change:
I don't see where you set your divider index.
You seem to be doing a lot of work with character arrays, so I'm guessing you're coming from a different language. Sticking with Strings will work fine.
You don't address the "teens". This looks like a simple oversight.
I've added those fixes while attempting maintain the original approach:
public static void main(String [] args) {
Scanner scInput = new Scanner(System.in);
String word = scInput.nextLine();
int total = 0;
int tensValue = 0; //number's tens value (i.e. 30)
int onesValue = 0; //ones value (i.e. 3)
int divider = word.indexOf('-');
String tens = null;
String ones = null;
if (divider != -1) {
tens = word.substring(0, divider);
ones = word.substring(divider + 1);
} else {
ones = word;
}
//searches for matches in String array for tens
if (tens != null) {
for (int u = 0; u < wTENS.length; u++) {
if (tens.equals(wTENS[u])) {
tensValue = nTENS[u];
total += tensValue;
}
}
}
//searches for matches in String array for ones
for(int u = 0; u < wONES.length; u++) {
if (ones.equals(wONES[u])) {
onesValue = nONES[u];
total += onesValue;
}
}
// if a "teen" override what's in total
for(int u = 0; u < wTEENS.length; u++) {
if (ones.equals(wTEENS[u])) {
total = nTEENS[u];
}
}
System.out.println(total);
}
Currently I have a method that asks user for an input string but only outputs the first 16 characters! The method is supposed to take in any length of string then output the characters in 4x4 blocks after it does the following: first row remains the same. Shift the second row one position to the left, then shifts the third row two positions to the left. Finally, shift the fourth row three positions to the left. As of now it will only output the first 4x4 block
Also I am not sure how I can change the method so it doesnt ask for user input
I would like it to use a given string like:
String text = shiftRows("WVOGJTXQHUHXICWYYMGHTRKQHQPWKYVGLPYSPWGOINTOFOPMO");
"WVOGJTXQHUHXICWYYMGHTRKQHQPWKYVGLPYSPWGOINTOFOPMO" is the given encrypted string I would like to use. but without asking for user input..I keep getting errors and incorrect outputs..please show how I might fix this
code I am using:
public class shiftRows {
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
String[] input= new String[4];
String[] output= new String[4];
System.out.println("Enter a String");
String inputStr = sc.next();
for (int i = 0, n = 0; i < 4; i++, n+=4) {
input[i] = inputStr.substring(0+n, 4+n);
}
// -
output[0] = input[0];
for(int i=1; i<4; i++)
{
output[i] = Shift(input[i],i);
}
for(int i=0; i<4; i++)
{
System.out.println(output[i]);
}
}
public static String Shift(String str, int shiftNum)
{
char[] out = new char[4];
if(shiftNum==1)
{
out[0]=str.charAt(1);
out[1]=str.charAt(2);
out[2]=str.charAt(3);
out[3]=str.charAt(0);
}
if(shiftNum==2)
{
out[0]=str.charAt(2);
out[1]=str.charAt(3);
out[2]=str.charAt(0);
out[3]=str.charAt(1);
}
if(shiftNum==3)
{
out[0]=str.charAt(3);
out[1]=str.charAt(0);
out[2]=str.charAt(1);
out[3]=str.charAt(2);
}
return new String(out);
}
}
Here's a good way to do it :
import java.util.Scanner;
public class shiftRows {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String inputStr = "WVOGJTXQHUHXICWYYMGHTRKQHQPWKYVGLPYSPWGOINTOFOPMO";
for (int i = 0 ; i < inputStr.length() ; i++){
System.out.print(inputStr.charAt(i));
if ((i + 1)%4 == 0) System.out.println();
}
}
}
If you want to stock it into a String, just concatenate at each loop and add a "\n" each time the if test is valid.
I have a test for a class that displays a word randomly chosen from an array.
I'm trying to display the word with several chars hidden
I have taken the string, then converted it to an array of chars, but I'm confused as to where to go from here.
import java.util.Scanner;
public class wordTest {
public static void main (String args[])
{
Scanner scanner = new Scanner(System.in);
String readString = scanner.nextLine();
char[] stringArray;
String [] gamewords = { "dog", "cat", "coffee", "tag", "godzilla", "gamera", "lightning", "flash", "spoon", "steak", "moonshine", "whiskey", "tango", "foxtrot", "ganymede"
, "saturn", "enterprise", "reliant", "defiant", "doom", "galapagos", "jidai", "sengoku"};
arrayWords wl = new arrayWords();
// Words w = new Words();
Word n = new Word();
int a = 0;
int b = gamewords.length;
RandNum rand = new RandNum(a,b);
n.setWord(gamewords[rand.nextRandomIntegerInRange()]);
stringArray = n.getWord().toCharArray();
int blank1 = 1;
int blank2 = 4;
RandNum blanks = new RandNum(blank1,blank2);
n.setWord(gamewords[rand.nextRandomIntegerInRange()]);
do{
int i = 0;
//scanner.nextLine();
for( i = 0; i < stringArray.length; i++){
for( i = 0 ; i < blanks.nextRandomIntegerInRange() ; i++ ){
stringArray[i] = '*';
}
System.out.println(stringArray[i]);
}
}while(scanner.nextLine().equals(""));
}
}
Since you haven't given clear definition on what you want to do, here I assume for every string, you are randomly masking 2 characters, in pseudo code, it looks like:
if inputString.length < 2 {
mask all character
} else {
loop until 2 character masked {
r = random from 0 to inputString.length-1
if (inputString[r] is not masked) {
set inputString[r] to mask character
}
}
}
some hints:
to make "inputString" modifiable, make use of a StringBuilder
Way to check if certain position is masked, you can either simply check if the character in the string == mask character, or you can use a Set to keep all masked position
In order to find out number of position masked, you can keep a counter, or simply use the size of the Set in 2 if you choose to use a Set.
Okay, so I think I've found the solution:
for (int i = 0; i < stringArray.length ; i++) {
stringArray[blanks.nextRandomIntegerInRange()] = '_';
System.out.print(stringArray[i] + " " );
}