Sort a string with small capital and numbers in Java
aAbcB1C23 .
Answer ABCabc123.
I tried sorting the array both ascending as well as decending but did not work as in both the ways ABC is coming in the middle. Any ideas ?
I'd like to solve with O(1) auxillary space and may be O(n log n) time ..
public class SortTheGivenStringAlphabetically {
public static void performAction() {
String input = "aAbcB1C23";
char[] inputCharArray = input.toCharArray();
sort(inputCharArray, 0, (inputCharArray.length) - 1);
for (int i = 0; i < inputCharArray.length; i++) {
System.out.println(inputCharArray[i]);
}
}
public static void sort(char[] array, int low, int high) {
if (low < high) {
int pi = partition(array, low, high);
sort(array, low, pi - 1);
sort(array, pi + 1, high);
}
}
private static int partition(char[] array, int low, int high) {
int pivot = array[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (array[j] <= pivot) {
i++;
char temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
char temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
public static void main(String[] args) {
performAction();
}
}
Create 3 ArrayLists.
Separate all characters from the input and add them to the specific ArrayList.
Then sort them using Collections.sort().
Finally combine all the characters in the order you want.
String input = "aAbcB1C23";
ArrayList<Character> capital = new ArrayList(),
simple = new ArrayList(),
numbers = new ArrayList();
for (Character c : input.toCharArray()) {
if (Character.isLetter(c)) {
if (Character.isUpperCase(c)) {
capital.add(c);
} else {
simple.add(c);
}
} else {
numbers.add(c);
}
}
Collections.sort(simple);
Collections.sort(capital);
Collections.sort(numbers);
StringBuilder output = new StringBuilder();
for (Character c : capital) {
output.append(c);
}
for (Character c : simple) {
output.append(c);
}
for (Character c : numbers) {
output.append(c);
}
System.out.println(output.toString());
Output:
ABCabc123
The meanness is that the natural order is '1' (49) < 'A' (65) < 'a' (97).
String input = "aAbcB1C23"; // Sorted: ABCabc123
char[] array = input.toCharArray();
sort(array, 0, (array.length) - 1);
So either you could reorder the wrongly sorted result:
output = output.replaceFirst("^([0-9]*)([A-z]*)$", "$2$1");
or map every concerned char to a correct value: easiest with a function:
int value(char ch) {
if ('A' <= ch && ch <= 'Z') {
return 100 + (ch - 'A');
} else if ('a' <= ch && ch <= 'z') {
return 200 + (ch - 'a');
} else if ('0' <= ch && ch <= '9') {
return 300 + (ch - '0');
} else {
return 400 + (int) ch;
}
}
Now compare value(array[i]).
First loop iterate no of times the no of character present in String.And last two loops run for constant time (78 times).So time complexity wise it could be effecient.
public static String SortSstring(String input) {
int []intArr=new int[78];
for(int i=0;i<input.length();i++)
intArr[input.charAt(i)-48] ++;
String OutputString="";
for(int i=17;i<78;i++){
OutputString+=String.valueOf(new char[intArr[i]]).replace('\0', (char)(i+48));
}
for(int i=0;i<10;i++){
OutputString+=String.valueOf(new char[intArr[i]]).replace('\0', (char)(i+48));
}
return OutputString;
}
}
One option is to use integer value of a character when doing comparison. To make numbers appear at the end we can add some fixed value to it (e.g. 100).
public static void main(String[] args) {
String input = "aAbcB1C23";
char[] charArray = input.toCharArray();
Character[] charObjectArray = ArrayUtils.toObject(charArray);
Arrays.sort(charObjectArray, new Comparator<Character>() {
#Override
public int compare(Character o1, Character o2) {
Integer i1 = convert(Integer.valueOf(o1));
Integer i2 = convert(Integer.valueOf(o2));
return i1.compareTo(i2);
}
private Integer convert(Integer original) {
if (original < 58) {
return original + 100;
}
return original;
}
});
System.out.println(new String(ArrayUtils.toPrimitive(charObjectArray)));
}
Related
At a user entered string, I am having a tough time with the counter. The code locates the most occurring character but where can I put counter that it counts the most occurring character. In Java, with the current code please. It's the last method.
import java.util.*;
public class newTest {
public static void main(String[] args) {
Scanner scnr = new Scanner(System.in);
System.out.println("Please enter a one line sentence:");
String words = scnr.nextLine();
findAlphabetMode(words);
}
public static void findAlphabetMode(String input){
int[] freq = new int[input.length()];
char mode = input.charAt(0);
boolean noMode = true;
int counter = 0;
int steadyCount = 0;
char string[] = input.toCharArray();
for (int i = 0; i < string.length; i++){
freq[i] = 1;
for(int j = i + 1; j < string.length; j++){
if(string[i] == string[j] && string[i] != ' ' && string[i] != 0){
freq[i]++;
//counter++;
}
if(counter > 1){
if(counter > steadyCount){
steadyCount = counter + 1;
counter = 0;
}
}
if(string[i] == string[j]){
noMode = false;
string[j] = 0;
counter++;
}
}
}
int max = freq[0];
for(int i = 0; i < freq.length; i++){
if(max < freq[i]){
max = freq[i];
mode = string[i];
noMode = false;
}
}
if (noMode) {
System.out.println("Mode: No Mode");
}
else {
System.out.println("The letter " + mode + " occurs " + steadyCount + " times");
}
}
}
`
Must not be that complicated, even without streams:
public static void findAlphabetMode(String input) {
var freq = new int['z'-'a'+1];
for (var ch : input.toLowerCase().toCharArray()) {
if (ch >= 'a' && ch <= 'z') {
freq[ch-'a'] += 1;
}
}
var max = 0; // index to maximum freq
for (var i = 1; i < freq.length; i++) {
if (freq[i] > freq[max]) {
max = i;
}
}
var ch = (char) ('a' + max);
System.out.printf("found %d times %c%n", freq[max], ch);
}
Not to hard to combine second loop into first loop:
public static void findAlphabetMode(String input) {
var freq = new int['z'-'a'+1];
var max = 0; // index to maximum freq
for (var ch : input.toLowerCase().toCharArray()) {
if (ch >= 'a' && ch <= 'z') {
if (++ freq[ch-'a'] > max) {
max = ch - 'a';
}
}
}
var ch = (char) ('a' + max);
System.out.printf("found %d times %c%n", freq[max], ch);
}
Note: this only counts letters a-z after converting to lower case.
You don't need a nested for loop. That makes your algorithm O(N^2) i.e. when your input string length doubles, the time taken increases fourfold.
You can put each letter in the input string into a Map<Character, Integer>, increasing the value each time you add an existing character, and then at the end find the key with the largest value. A succinct way of doing this is to use streams:
public static void findAlphabetMode(String input) {
input.chars()
.boxed()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.ifPresentOrElse(
e -> System.out.printf("The letter %c occurs %d times%n", e.getKey(), e.getValue()),
() -> System.out.println("No mode"));
}
If you still prefer loops you can do it like so.
iterate across the string, checking only letters
use map.merge to compute the frequency.
String s =
"To be or not to be, that is the question.";
Map<Character, Integer> map = new HashMap<>();
for (Character c : s.toCharArray()) {
if (Character.isLetter(c)) {
map.merge(c, 1, Integer::sum);
}
}
Now that the frequency is counted, just find the largest
first, make certain characters exist
otherwise, iterate across the entry set finding the maximum value and saving the associated character.
if (map.isEmpty()) {
System.out.println("Mode: No Mode");
} else {
Entry<Character, Integer> result = null;
char chr = ' ';
int count = 0;
for (Entry<Character, Integer> e : map.entrySet()) {
int val = e.getValue();
if (val > count) {
count = val;
chr = e.getKey();
}
}
System.out.printf("The letter `%c` occurs %d times.%n", chr, count );
}
prints
The letter `t` occurs 6 times.
If you want to ignore case, you can do the following in the first loop.
for (Character c : s.toLowerCase().toCharArray()) {
...
}
You don't need to separately increment counter, since you are already calculating frequency for each character, in an array, you can simply loop, over the array and find your maximum occuring character. Here is a simplified version of your code:
import java.util.*;
public class newTest {
public static void main(String[] args) {
Scanner scnr = new Scanner(System.in);
System.out.println("Please enter a one line sentence:");
String words = scnr.nextLine();
findAlphabetMode(words);
}
public static void findAlphabetMode(String input){
int[] freq = new int[input.length()];
char mode = input.charAt(0);
char string[] = input.toCharArray();
for (int i = 0; i < string.length; i++){
freq[i] = 1;
for(int j = i + 1; j < string.length; j++){
if(string[i] == string[j]){
freq[i]++;
}
}
}
int max = freq[0];
for(int i = 0; i < freq.length; i++){
if(max < freq[i]) {
max = freq[i];
mode = string[i];
}
}
System.out.println("The letter " + mode + " occurs " + max + " times");
}
}
You have been given a binary string containing only the characters '1' and '0'.
Calculate how many characters of the string need to be changed in order to make the binary string such that each of its substrings of at least a certain length contains at least one "1" character.
I came to think of the following idea but it fails for many testcases:
public static int minimumMoves(String s, int d) {
int n = s.length();
int i=0, answer = 0;
while(i<n)
{
boolean hasOne = false;
int j=i;
while(j<n && j<i+d)
{
if(s.charAt(j) == '1')
{
hasOne = true;
break;
}
j++;
}
if(!hasOne) {
answer++;
i += d;
}
else i++;
}
return answer;
}
Also my algorithm runs on O(|s|2) time. Can anyone suggest ideas on O(|s|) time?
Just throwing off an idea:
return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().filter(str -> str.contains("1")).count()
You just need to break ensure there is no run of d zeros.
public static int minimumMoves(String s, int d) {
int result = 0;
int runLength = 0;
for(char c: s.toCharArray()) {
if (c == '0') {
runLength += 1;
if (runLength == d) { // we need to break this run
result += 1;
runLength = 0;
}
} else {
runLength = 0;
}
}
return result;
}
I used the sliding window technique and Deque to solve this. This is my accepted solution:
public static int minimumMoves(String s, int d) {
int n = s.length();
Deque<Character> dq = new LinkedList<>();
int count = 0, answer = 0;
for(int i=0; i<d; i++)
{
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
}
if(count == 0) {
answer++;
count++;
dq.removeLast();
dq.addLast('1');
}
int i=d;
while(i<n)
{
if(dq.getFirst() == '1') count--;
dq.removeFirst();
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
if(count == 0)
{
answer++;
dq.removeLast();
dq.addLast('1');
count++;
}
i++;
}
return answer;
}
You just need to use a sliding window and a count of 1s so far at each index. Use a sliding window of d and if you don't see any ones so far, update the last index of that window with 1 and increment the result.
Code below:
public static int minimumMoves(String s, int d) {
int n = s.length();
int[] count = new int[n+1];
int res = 0;
for ( int i = 1; i <= d; i++ ) {
if ( s.charAt(i-1) == '1') count[i] = count[i-1]+1;
else count[i] = count[i-1];
}
if ( count[d] == 0 ) {
res++;
count[d] = 1;
}
for ( int i = d+1; i <= n; i++ ) {
if ( s.charAt(i-1) == '0' ) {
count[i] = count[i-1];
int ones = count[i] - count[i-d];
if ( ones == 0 ) {
count[i] = count[i-1] + 1;
res++;
}
} else {
count[i] = count[i-1] + 1;
}
}
return res;
}
Thought of another implementation you can do for this by working from the maximum possible changes (assumes at start that all values are '0' in String), reduce it when it finds a '1' value, and then jump to the next substring start. This allows it to run in O(n) and Ω(n/m) (n = String length, m = Substring length).
public static int minimumMoves(String s, int d)
{
char[] a = s.toCharArray();
//Total possible changes (not counting tail)
if(a.length < d)
return 0;
int t = (int) a.length / d;
//Total possible changes (counting tail)
//int t = (int) Math.ceil((double) a.length / (double) d);
for(int i = 0; i < a.length; i++)
{
if(a[i] == '1')
{
t--;
//Calculate index for start of next substring
i = (i / d + 1) * d - 1;
}
}
return t;
}
Given a string representing the starting number and a maximum number of changes allowed, create the largest palindromic string of digits possible or the string -1 if it's impossible to create a palindrome under the contstraints.
I wrote a code who answer on the questions, but i have an error that i dont know where it is, or if even the code work.
static String highestValuePalindrome(String s, int n, int k) {
for(int i =0 ; i < n ; i++){
char[] ch =s.toCharArray();
if(n==1)
return s ;
else if ((ch[i] != ch[n-i-1]) && (k != 0) ){
ch[i] = ch[n-i-1] = 9 ;
k--;
}
}
String str = new String(ch);
return str ;
}
Output Format
Print a single line with the largest number that can be made by changing no more than digits. If this is not possible, print -1.
Sample Input
n=4, k=1
3943
Sample Output
3993
Sample Input
n=6, k=3
092282
Sample Output
992299
Sample Input
n=4, k=1
0011
Sample Output
-1
First of all there is no need to pass n as a parameter because it's just the length of the string. Secondly, this is not the complete program. I have made many changes to the given code.
public class largestPalindorme {
public static void main(String[] args) {
System.out.println(highestValuePalindrome("0011", 1));
}
static String highestValuePalindrome(String s, int k) {
char[] ch = s.toCharArray();
int n = s.length(); // which is same as n which you passed as parameter
int minChangesRequired = MinumumChangesNeeded(s);
//if the changes required to make the given string a palindrome is less then k then only it will go inside or it will return -1
if (k >= minChangesRequired) {
int diff = 0;
if (k > minChangesRequired) {
diff = k - minChangesRequired;
for (int l = 0; l < diff; l++) {
ch[l] = '9';
ch[n - l - 1] = '9';
}
}
for (int i = diff; i < n - diff / 2; i++) {
if (ch[i] != ch[n - i - 1]) {
//if checks which number is greater
int greater = Integer.parseInt(String.valueOf(ch[i])) > Integer.parseInt(String.valueOf(ch[n - i - 1])) ? Integer.parseInt(String.valueOf(ch[i])) : Integer.parseInt(String.valueOf(ch[n - i - 1]));
//replaces the smaller number from the greater number.
if (Integer.parseInt(String.valueOf(ch[i])) != greater) {
ch[i] = ch[n - i - 1];
} else {
ch[n - i - 1] = ch[i];
}
}
}
String str = new String(ch);
return str;
}
return "-1";
}
//this function returns the minimum changes we need to do to make it a palindrome.
public static int MinumumChangesNeeded(String s) {
int count = 0;
char[] ch = s.toCharArray();
int n = s.length();
for (int i = 0; i < n / 2; i++) {
if (ch[i] != ch[n - i - 1]) {
count++;
}
}
return count;}}
For a given positive integer N of not more than 1000000 digits, write the value of the smallest palindrome larger than N to output.
Here is my code:
public class Palin {
public static String reverseString(String s) {
String newS = "";
for(int i = s.length() - 1; i >= 0; i--)
newS += s.charAt(i);
return newS;
}
public static String getPalin(String s) {
int lth = s.length();
String left = "", mid = "", right = "", newS = "";
if(lth % 2 != 0) {
left = s.substring(0, lth / 2);
mid = s.substring(lth / 2, lth / 2 + 1);
right = reverseString(left);
newS = left + mid + right;
if(s.compareTo(newS) < 0) return newS;
else {
int temp = Integer.parseInt(mid);
temp++;
mid = Integer.toString(temp);
newS = left + mid + right;
return newS;
}
}
else {
left = s.substring(0, lth / 2 - 1);
mid = s.substring(lth / 2 - 1, lth / 2);
right = reverseString(left);
newS = left + mid + mid + right;
if(s.compareTo(newS) < 0) return newS;
else {
int temp = Integer.parseInt(mid);
temp++;
mid = Integer.toString(temp);
newS = left + mid + mid + right;
return newS;
}
}
}
public static void main(String[] args) throws java.lang.Exception {
Scanner input = new Scanner(System.in);
//Scanner input = new Scanner(System.in);
int k = input.nextInt();
String[] s = new String[k];
for(int i = 0; i < k; i++) {
s[i] = input.next();
}
for(int i = 0; i < k; i++) {
System.out.println(getPalin(s[i]));
}
}
}
My idea is use a String represent for a number. I divide this String into 2 part, coppy first part and reverse it for second part. I think my solve is correct but it not fast enough. I need a more efficient algorithm.
Thanks
EDITED
Since you said that:
For a given positive integer N of not more than 1000000 digits
My previous solution won't work since I have converted them to int and an int can't accommodate 1000000 digits. Thus I have made a new approach, an approach that doesn't need any String to int conversion.
Refer to the code and comment below for details.
CODE:
package main;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Scanner input = new Scanner(System.in);
int k = Integer.parseInt(input.nextLine());
String[] s = new String[k];
for (int i = 0; i < k; i++) {
s[i] = input.nextLine();
}
for (int i = 0; i < k; i++) {
System.out.println(getPalin(s[i]));
}
input.close();
}
public static String getPalin(String s) {
// initialize the result to "" since if input is 1 digit, nothing is printed
String result = "";
// if input is greater than 1000000 digits
if (s.length() >= 1000000) {
// return the highest palindrome less than 1000000
result = "999999";
} else if (s.length() > 1) {
// get the middle index of the string
int mid = s.length() % 2 == 0 ? s.length() / 2 : (s.length() / 2) + 1;
// get the left part of the string
String leftPart = getPalindrome(s.substring(0, mid));
if (s.length() % 2 == 0) {
// attach the left part and the reverse left part
result = leftPart + new StringBuilder(leftPart).reverse().toString();
} else {
// attach the left part and the reverse left part excluding the middle digit
result = leftPart
+ new StringBuilder(leftPart.substring(0, leftPart.length() - 1)).reverse().toString();
}
// check if the new result greater than 1000000 digits
if (result.length() >= 1000000) {
// return the highest palindrome less than 1000000
result = "999999";
}
}
return result;
}
public static String getPalindrome(String param) {
String result = "";
// iterate through the string from last index until index 0
for (int i = param.length() - 1; i >= 0; i--) {
// get the char at index i
char c = param.charAt(i);
/*
* increment char since the next palindrome is the current digit + 1. Example:
* User input is 121, then param will be 12 so the next is 13
*/
c++;
/*
* check if the current character is greater than '9', which means it is not a
* digit after incrementing
*/
if (c > '9') {
// set the current char to 0
c = '0';
// check if index is at index 0
if (i - 1 < 0) {
// if at index 0 then add '1' at start
result = '1' + result;
} else {
// if not then append c at result
result = result + c;
}
} else {
// check if index is at index 0
if (i - 1 < 0) {
// if not then prepend c at result
result = c + result;
} else {
// if not then get the rest of param then append c and result
result = param.substring(0, i) + c + result;
}
break;
}
}
return result;
}
}
How to calculate the 2's Complement of a Hex number in Android/Java.
For Example :
String x = 10011010;
1's complement of x = 01100101;
2's complement is 01100110;
How I can pro-grammatically achieve in Java?
I had tried the following code to convert the binary to its 1's compliment:
public String complementFunction(String bin) {
String ones = "";
for (int i = 0; i < bin.length(); i++) {
ones += flip(bin.charAt(i));
}
return ones;
}
// Returns '0' for '1' and '1' for '0'
public char flip(char c) {
return (c == '0') ? '1' : '0';
}
But I'm not able to get its two's complement.
Thanks for your help everyone.
I got the solution and it is as follows :
public String twosCompliment(String bin) {
String twos = "", ones = "";
for (int i = 0; i < bin.length(); i++) {
ones += flip(bin.charAt(i));
}
int number0 = Integer.parseInt(ones, 2);
StringBuilder builder = new StringBuilder(ones);
boolean b = false;
for (int i = ones.length() - 1; i > 0; i--) {
if (ones.charAt(i) == '1') {
builder.setCharAt(i, '0');
} else {
builder.setCharAt(i, '1');
b = true;
break;
}
}
if (!b)
builder.append("1", 0, 7);
twos = builder.toString();
return twos;
}
// Returns '0' for '1' and '1' for '0'
public char flip(char c) {
return (c == '0') ? '1' : '0';
}
Thanks to all for helping.
This wikipedia section explains an easy way to get the 2's complement: Get the 1's complement, then add 1 (in binary logic). So you can use the complementFunction you already have, then go through the String backwards. If you find a 1, flip it and continue. If you find a 0, flip it and stop.
String twos = "";
for (int i = bin.length() - 1; i >= 0; i--) {
if (bin.charAt(i) == '1') {
twos = "0" + twos;
} else {
twos = bin.substring(0, i) + "1" + two;
break;
}
twos = flip(bin.charAt(i));
}
return twos;
#BackSlash's comment above is intriguing. This answer is the full program written based on this idea:
import java.time.temporal.ValueRange;
import java.util.Scanner;
//This program generates convert decimal to binary
public class ConvertDecimalToBinary {
public static int getNumberOfBytes(int n) {
int bytes = 0;
ValueRange byteRange = ValueRange.of(Byte.MIN_VALUE, Byte.MAX_VALUE);
ValueRange shortRange = ValueRange.of(Short.MIN_VALUE, Short.MAX_VALUE);
ValueRange intRange = ValueRange.of(Integer.MIN_VALUE, Integer.MAX_VALUE);
if (byteRange.isValidValue(n)) {
bytes = 1;
} else if (shortRange.isValidValue(n)) {
bytes = 2;
} else if (intRange.isValidValue(n)) {
bytes = 4;
}
return bytes;
}
//Convert a positive decimal number to binary
public static String convertPositiveNumberToBinary(int n, int bytes,boolean reverse) {
int bits = 8 * bytes;
StringBuilder sb = new StringBuilder(bits); //in-bits
if (n == 0) {
sb.append("0");
} else {
while (n > 0) {
sb.append(n % 2);
n >>= 1; //aka n/2
}
}
if (sb.length() < bits) {
for (int i = sb.length(); i < bits; i++) {
sb.append("0");
}
}
if (reverse) {
return sb.toString();
} else {
return sb.reverse().toString();
}
}
//Convert negative decimal number to binary
public static String convertNegativeNumberToBinary(int n, int bytes) {
int m = -n; //conver to positve
String binary = convertPositiveNumberToBinary(m,bytes,true);
int len = binary.length();
StringBuilder sb = new StringBuilder(len); //in-bits
boolean foundFirstOne = false;
for(int i=0; i < len;i++) {
if(foundFirstOne) {
if(binary.charAt(i) == '1') {
sb.append('0');
}
else {
sb.append('1');
}
}
else {
if(binary.charAt(i) == '1') {
foundFirstOne = true;
}
sb.append(binary.charAt(i));
}
}
return sb.reverse().toString();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextInt()) {
int n = scanner.nextInt();
int bytes = getNumberOfBytes(n);
String binary;
if(n >= 0) {
binary = convertPositiveNumberToBinary(n,bytes,false);
}
else {
binary = convertNegativeNumberToBinary(n,bytes);
}
System.out.println(String.format("Binary representation of {%s} is {%s}",n,binary));
}
scanner.close();
}
}