Replacing two characters with one character in a char array - java

How to replace two characters with one character in a char array? Let me explain a bit more. I have a char array of length n . In this char array i want to replace two characters with one character in a specified index i. In this process the array length is going to decrease by 1.
The idea which i came to my mind is, first create a new char array of length n-1 then copy all elements from index 0 to index i (i excluding) then insert desired character at index i then copy elements from index i+2 (i including) to the index n-1. But this process require two times for loop. Is there any better approach which can do the same in efficient manner.

Or a more efficient way of doing this is to use a StringBuilder which is a wrapper for char[] and let it do it for you.
char[] chars = "Hello".toCharArray();
StringBuilder sb = new StringBuilder();
sb.append(chars);
sb.replace(2, 4, "L");
System.out.println(sb);
prints
HeLo
You can look at the code for replace to see how it does it.

Copy array portions with System.arraycopy() instead of iterating over its elements.

Given that you want a new array object, there's no faster way than by copying each array element once, so there's no more efficient method than this. If you use two calls to System.arraycopy(), you don't have to write the loops yourself.
If you don't need a new array object, you could just move the higher-numbered array elements down by one, which involves just half the number of copies -- but then you're going to need to keep track of the length some other way.

It could use a single for loop. Just put in an IF statement indicating if iteration (i) = index you want to replace then do a different operation rather than just copy.
Written in basic:
For i = 0 to n - 1
If i = x then
arrayCopy(i) = replaceChars
Else
arrayCopy(i) = arraySource(i)
End If
Next

Related

Algorithm, Big O notation: Is this function O(n^2) ? or O(n)?

This is code from a algorithm book, "Data structures and Algorithms in Java, 6th Edition." by by Michael T. GoodRich, Roberto Tamassia, and Michael H. Goldwasser
public static String repeat1(char c, int n)
{
String answer = "";
for(int j=0; j < n; j++)
{
answer += c;
}
return answer;
}
According to the authors, the Big O notation of this algorithm is O(n^2) with reason:
"The command, answer += c, is shorthand for answer = (answer + c). This
command does not cause a new character to be added to the existing String
instance; instead it produces a new String with the desired sequence of
characters, and then it reassigns the variable, answer, to refer to that new
string. In terms of efficiency, the problem with this interpretation is that
the creation of a new string as a result of a concatenation, requires time
that is proportional to the length of the resulting string. The first time
through this loop, the result has length 1, the second time through the loop
the result has length 2, and so on, until we reach the final string of length
n."
However, I do not understand, how this code can have O(n^2) as its number of primitive operations just doubles each iteration regardless of the value of n(excluding j < n and j++).
The statement answer += c requires two primitive operations each iteration regardless of the value n, therefore I think the equation for this function supposed to be 4n + 3. (Each loop operates j
Or, is the sentence,"In terms of efficiency, the problem with this interpretation is that the creation of a new string as a result of a concatenation, requires time that is proportional to the length of the resulting string.," just simply saying that creating a new string as a result of a concatenation requires proportional time to its length regardless of the number of primitive operations used in the function? So the number of primitive operations does not have big effects on the running time of the function because the built-in code for concatenated String assignment operator's running time runs in O(n^2).
How can this function be O(n^2)?
Thank you for your support.
During every iteration of the loop, the statement answer += c; must copy each and every character already in the string answer to a new string.
E.g. n = 5, c = '5'
First loop: answer is an empty string, but it must still create a new string. There is one operation to append the first '5', and answer is now "5".
Second loop: answer will now point to a new string, with the first '5' copied to a new string with another '5' appended, to make "55". Not only is a new String created, one character '5' is copied from the previous string and another '5' is appended. Two characters are appended.
"n"th loop: answer will now point to a new string, with n - 1 '5' characters copied to a new string, and an additional '5' character appended, to make a string with n 5s in it.
The number of characters copied is 1 + 2 + ... + n = n(n + 1)/2. This is O(n2).
The efficient way to constructs strings like this in a loop in Java is to use a StringBuilder, using one object that is mutable and doesn't need to copy all the characters each time a character is appended in each loop. Using a StringBuilder has a cost of O(n).
Strings are immutable in Java. I believe this terrible code is O(n^2) for that reason and only that reason. It has to construct a new String on each iteration. I'm unsure if String concatenation is truly linearly proportional to the number of characters (it seems like it should be a constant time operation since Strings have a known length). However if you take the author's word for it then iterating n times with each iteration taking a time proportional to n, you get n^2. StringBuilder would give you O(n).
I mostly agree with it being O(n^2) in practice, but consider:
Java is SMART. In many cases it uses StringBuilder instead of string for concatenation under the covers. You can't just assume it's going to copy the underlying array every time (although it almost certainly will in this case).
Java gets SMARTER all the time. There is no reason it couldn't optimize that entire loop based on StringBuilder since it can analyze all your code and figure out that you don't use it as a string inside that loop.
Further optimizations can happen--Strings currently use an array AND an length AND a shared flag (And maybe a start location so that splits wouldn't require copying, I forget, but they changed that split implementation anyway)--so appending into an oversized array and then returning a new string with a reference to the same underlying array but a higher end without mutating the original string is altogether possible (by design, they do stuff like this already to a degree)...
So I think the real question is, is it a great idea to calculate O() based on a particular implementation of a language-level construct?
And although I can't say for sure what the answer to that is, I can say it would be a REALLY BAD idea to optimize on the assumption that it was O(n^2) unless you absolutely needed it--you could take away java's ability to speed up your code later by hand optimizing today.
ps. this is from experience. I had to optimize some java code that was the UI for a spectrum analyzer. I saw all sorts of String+ operations and figured I'd clean them all up with .append(). It saved NO time because Java already optimizes String+ operations that are not in a loop.
The complexity becomes O(n^2) because each time the string increase the length by one and to create it each time you need n complexity. Also, the outer loop is n in complexity. So the exact complexity will be (n * (n+1))/2 which is O(n^2)
For example,
For abcdefg
a // one length string object is created so complexity is 1
ab // similarly complexity is 2
abc // complexity 3 here
abcd // 4 now.
abcde // ans so on.
abcdef
abcedefg
Now, you see the total complexity is 1 + 2 + 3 + 4 + ... + n = (n * (n+1))/2. In big O notation it's O(n^2)
Consider the length of the string as "n" so every time we need to add the element at the end so iteration for the string is "n" and also we have the outer for loop so "n" for that, So as a result we get O(n^2).
That is because:
answer += c;
is a String concatenation. In java Strings are immutable.
It means concatenated string is created by creating a copy of original string and appending c to it. So a simple concatenation operation is O(n) for n sized String.
In first iteration, answer length is 0, in second iteration its 1, in third its 2 and so on.
So you're doing these operations every time i.e.
1 + 2 + 3 + ... + n = O(n^2)
For string manipulations StringBuilder is the preferred way i.e. it appends any character in O(1) time.

Why exactly is this required in a reverse string program for Java?

I'm relatively new to Java and I have been looking at a reverse string code for Java. I understand the majority of it, but this one part of the code I do not understand. At the For loop I am required to subtract -1 from the integer length. Why exactly am I needed to do this? Without this the code fails to execute, and I'd like to know to grasp a greater understanding of loops in the future
String start = "";
String end = "";
Scanner input = new Scanner(System.in);
System.out.println("Enter a string");
start = input.nextLine();
int length = start.length();
for(length = length - 1 ; length >= 0 ; length--)
end = end + start.charAt(length);
System.out.println("This string reversed is " + end);
Usually you can check Javadoc on Eclipse (if you are using it) to see more information about your code.
Said that, this is literally from Javadoc
char java.lang.String.charAt(int index)
Returns the char value at the specified index. An index ranges from 0
to length() - 1. The first char value of the sequence is at index 0,
the next at index 1, and so on, as for array indexing.
If still not clear maybe an image could help:
A string can be of any length, but when accessing .charAt() you're accessing a data structure with an index.
These work on a system that starts with the first element at 0 in Java, as opposed to 1.
For example, if you wanted to access the first letter in the string, it would be start.charAt(0).
If the length of the variable 'start' is equal to n, then the index must be n - 1 (length - 1) to access the same corresponding value/char in the data structure.
If you don't use length - 1, you effectively access a char that doesn't exist. Say that the length of 'start' is 8, then characters will only occupy .charAt(0) to .charAt(7). If you try to access .charAt(8) using just length, there is no data to access as it's beyond the array limit and therefore will fail to execute.
I'll do a quick rundown of the code too as I always feel theory helps with a familiar context. I don't wish to be patronising, I just want to reinforce the knowledge.
start = input.nextLine();
int length = start.length();
for(length = length - 1 ; length >= 0 ; length--)
end = end + start.charAt(length);
In your code example you:
Take in an input (start)
Find the length of the input (length)
Enter a for loop, where 'length' is subtracted by 1 to get the correct index. If 'length' is bigger than or equal to 0, it is decremented by 1 (moving the index down by 1).
The char at the index position in the array is then added to the variable 'end'.
This is then repeated to take the indexed letter from the string 'start' and place them at the front of the new string 'end', therefore reversing the order.
Hope this has helped!
Strings, and more generally, arrays, are zero indexed in C, C++, Java. Character 1 is at position 0, character 2 is at position 1, etc.
For the last character, 'n', it is at position 'n-1'.
a string of length n has characters at index 0 - (n-1), hence the initialization. It would be more appropriate to call that var index.
Most data structures are indexed starting from "0" rather than "1". (I.e. the index of the first element is "0") As such, the index of the last element is equal to the number of elements (i.e. length) - 1. Thus, if you want to start from the last element, then you must start from index length - 1.
To answer your question, lets get back to some basics.
When we learnt Strings for first time, we stated its each letter's positions i.e. Index Position , starting from 0 till the end.
But here a twist comes.
When we use the length() function, it tells the total number of characters in the string, hence, it counts the first letter as 1 and and not 0 as in the case of Index Position.
So, while executing a loop which is using the string's length value, we reduce the length value by 1 so as to get the proper index positions of all the characters of the particular string.
Eg -
I am happy.
In this sentence, the length is 10 but the index position of I is 0 and similarly, the index position of y is 9.
Hope you understood the thing.

how to find the most frequent character in a big string using java?

i'm working on an assignment that i have to find the most four frequent characters in a string.
i write this so far.
import java.util.Scanner;
public class FindTheMostOccur
{
public static void main (String[] args)
{
String input;
String example = "how to find the most frequent character in a big string using java?";
String[] array = new String[example.length()];
for (int i = 97; i < 123; i++)
{
int mostFrequent =0;
for( int j = 0; j < example.length(); j++)
{
if(example.charAt(j) == i)
{
++mostFrequent;
}
}
System.out.println( (char)i + " is showing " + mostFrequent+ " times ");
}
}
}
Here is the output for this example.
a is showing 5 times
b is showing 1 times
c is showing 2 times
d is showing 1 times
e is showing 4 times
f is showing 2 times
g is showing 3 times
h is showing 3 times
i is showing 5 times
j is showing 1 times
k is showing 0 times
l is showing 0 times
m is showing 1 times
n is showing 5 times
o is showing 3 times
p is showing 0 times
q is showing 1 times
r is showing 4 times
s is showing 3 times
t is showing 6 times
u is showing 2 times
v is showing 1 times
w is showing 1 times
x is showing 0 times
y is showing 0 times
in this examle : t, a,i,n
I DON"T NEED SOMEONE TO COMPLETE THE PROGRAM FOR ME, however i need some ideas how to find the most four frequent character in this example.
The simplest algorithm I can think of off hand is that instead of doing multiple passes do a single pass.
Create a HashMap mapping from character to count.
Each time you find a character if it is not in the map, add it with value 1. If it is in the map increment the count.
At the end of the loop your HashMap now contains the count for every character in the String.
Take the EntrySet from the HashMap and dump it into a new ArrayList.
Sort the ArrayList with a custom comparator that uses entry.getValue() to compare by.
The first (or last depending on the sort direction) values in the ArrayList will be the ones you want.
How about this?
int count[] = new int[1000];// all with zero
Then for each character from the string, do count[]++ like this way
count['c']++;
count['A']++;
At the end, find out which index holds the maximum value. Then just print the ascii of that index.
Ok, here're some ideas:
To find the 4 most frequent characters, you must first know the frequency for all the characters. So, you would need to store the frequency somewhere. Currently, you are just printing the frequency of each character. You can't compare that way. So, you need a data structure.
Here we are talking about mapping from a chararacter to its count. Possibly you need a hash table. Look out for the hash table implementation in Java. You will find HashMap, LinkedHashMap, TreeMap.
Since you want the 4 most frequent characters, you need to order the characters by their frequency. Find out what kind of map stores the elements in sorted order. Note: You need to sort the map by values, not keys. And sort it in descending order, which is obvious.
Using Array:
There is another approach you can follow. You can create an array of size 26, assuming you only want to count frequency of alphabetic characters.
int[] frequency = new int[26];
Each index of that array correspond to the frequency of a single character. Iterate over the string, and increment the index corresponding to the current character by 1.
You can do character to index mapping like this:
int index = ch - 'a';
So, for character 'a', the index will be 0, for character 'b', index will be 1, so on. You might also want to take care of case sensitivity.
Problem with the array approach is, once you sort the array to get 4 most frequent character, you've lost the character to index mapping. So, you would need to have some way to sort the indices along with the frequency at those indices. Yes you're right. You need another array here.
But, will having 2 arrays make your problem easy? No. Because it's difficult to sort 2 arrays in synchronization. So what to do? You can create a class storing index and character. Maintain an array of that class reference, of size 26. Then find your way out to port the array approach to this array.
What data structures are you allowed to use?
I'm thinking that you can use a priority queue and increment the priority of the node containing the character that is being repeated. And when you are done, the first index would contain the node with the most repeated character
I got another idea that you can do it using an array only.
Well you have 26 letters in the Alphabet. The ASCII code of the lowercase letters range from 97 to 122(you can make every letter a lower case using .lowercase() or something similar).
So for each character, get its ASCII code, do the ASCII code -97 and increment it.
Simple,and only need an array.

array index out of bounds exception in a while loop

I'm having this interesting ArrayIndexOutofBounds exception.
The code is this:
int m = 0;
while (scan.hasNextInt())
{
intArray[m++] = scan.NextInt();
}
I'm merely scanning a bunch of integers into an array, but I always get an ArrayIndexOutofBounds error. I thought my int m was already initialized to zero?
Thanks
inputString.length() returns the number of characters in the string. it does not necessarily correspond to the number of numbers in your string.You will want to add another condition to your while statement to ensure that m doesn't get larger than intArray.length. Also you probably want to step through the code with a debugger to determine exactly when the array runs out of space.
Since java arrays are fixed size, if you don't know what the size of your input is going to be, you should instead use ArrayList<Integer> to store your input.
Does the array have any elements in it to start off with?
On future iterations of the loop, m is not zero because you increment it inside the loop.
ArrayIndexOutofBounds means your array isn't big enough to hold the number of values you are putting in it. Where are you initializing the array intArray?
If you don't know how many values the scanner has upfront, which I would assume to be the case, you might want to use an ArrayList instead.
Something like this should work..
List<Integer> intArray = new ArrayList<Integer>();
while (scan.hasNextInt())
{
intArray.add(scan.NextInt());
}
If you need the final results in an array rather then an ArrayLIst, you can use
Integer[] newArray = (Integer[])intArray.toArray();

Find longest series of ones in a binary digit array

How would I find the longest series of ones in this array of binary digits - 100011101100111110011100
In this case the answer should be = 11111
I was thinking of looping through the array and checking every digit, if the digit is a one then add it to a new String, if its a zero re-start creating a new String but save the previously created String. When done check the length of every String to see which is the longest. I'm sure there is a simpler solution ?
Your algorithm is good, but you do not need to save all the temporary strings - they are all "ones" anyway.
You should simply have two variables "bestStartPosition" and "bestLength". After you find a sequence of "ones" - you compare the length of this sequence with saved "bestLength", and overwrite both variables with new position and length.
After you scanned all array - you will have the position of the longest sequence (in case you need it) and a length (by which you can generate a string of "ones").
Java 8 update with O(n) time complexity (and only 1 line):
int maxLength = Arrays.stream(bitStr.split("0+"))
.mapToInt(String::length)
.max().orElse(0);
See live demo.
This also automatically handles blank input, returning 0 in that case.
Java 7 compact solution, but O(n log n) time complexity:
Let the java API do all the work for you in just 3 lines:
String bits = "100011101100111110011100";
LinkedList<String> list = new LinkedList<String>(Arrays.asList(bits.split("0+")));
Collections.sort(list);
int maxLength = list.getLast().length(); // 5 for the example given
How this works:
bits.split("0+") breaks up the input into a String[] with each continuous chain of 1's (separated by all zeros - the regex for that is 0+) becoming an element of the array
Arrays.asList() turns the String[] into a List<String>
Create and populate a new LinkedList from the list just created
Use collections to sort the list. The longest chain of 1's will sort last
Get the length of the last element (the longest) in the list. That is why LinkedList was chosen - it has a getLast() method, which I thought was a nice convenience
For those who think this is "too heavy", with the sample input given it took less than 1ms to execute on my MacBook Pro. Unless your input String is gigabytes long, this code will execute very quickly.
EDITED
Suggested by Max, using Arrays.sort() is very similar and executes in half the time, but still requires 3 lines:
String[] split = bits.split("0+");
Arrays.sort(split);
int maxLength = split[split.length - 1].length();
Here is some pseudocode that should do what you want:
count = 0
longestCount = 0
foreach digit in binaryDigitArray:
if (digit == 1) count++
else:
longestCount = max(count, maxCount)
count = 0
longestCount = max(count, maxCount)
Easier would be to extract all sequences of 1s, sort them by length and pick the first one. However, depending on the language used it would probably be only a short version of my suggestion.
Got some preview code for php only, maybe your can rewrite to your language.
Which will say what the max length is of the 1's:
$match = preg_split("/0+/", "100011101100111110011100", -1, PREG_SPLIT_NO_EMPTY);
echo max(array_map('strlen', $match));
Result:
5

Categories