What is the best way to check if a string index is in bounds? Let's say we are checking a String for index i-1 or i+1 because you cannot say != null.
Example:
for (int i = 0; i < string.length(); i++)
{
if (string.charAt(i+1) == '#' && string.charAt(i - 1) != '1')
{
}
}
Should you just check the length of the string and see if it is within it?
string.charAt(i+1) == '#'
Yes, I think you need to make sure i+1 is not greater than String length.
Example:
if( (i+1) < string.length() && (i-1) >= 0 && (yourcode))
{
}
Why not just check the length of the string?
if(myString.length() - 1 > i)
I've always modified the length (and/or start) of the loop in these cases... these are all good answers - there's no one way to do it, but this is how I would do it:
for (int i = 1; i < string.length() - 1; i++)
{
if (string.charAt(i+1) == '#' && (i != 1 || string.charAt(i - 1) != '1'))
{
}
}
EDIT: After considering all of the situations that this code entails, I wouldn't necessarily do this in this manner, but find a cleaner way to express exactly what I'm trying to accomplish
The simplest way is to change your for loop like this:
for (int i = 1; i < string.length() - 1; i++)
{
if (string.charAt(i+1) == '#' && string.charAt(i - 1) != '1')
{
}
}
Explanation:
string.charAt(i - 1) implies that you might read position i-1 of the string. Since 0 is the lowest valid value you can start the iteration with i = 1
string.charAt(i + 1) implies that you might read position i+1 of the string. Since string.length() - 1 is the highest valid value you need to end your iteration at i == string.length() - 2. Since the for-loop checks the condition before entering the loop using i < string.length() - 1 will be just right.
I would try with this code.
for (int i = 1; string!= null && string.length() >= 3 && i < string.length() - 1; i++)
//it solve the case of String == null and string too short
//it optimize the max number of cycles
{
if (string.charAt(i+1) == '#' && string.charAt(i - 1) != '1')
{
}
}
Related
This is my function which takes a string as input for example aabbaaa. I am deleting the character if the next one to it is the same. In this way I am removing consecutive occurrences of a character i.e the string will become aba. But it is throwing me indexoutofbounds exception.
static int alternatingCharacters(String s)
{
StringBuilder sb = new StringBuilder(s);
try
{
for(int i = 0; i < sb.length(); i++)
{
while (sb.charAt(i) == sb.charAt(i+1) && i+1<sb.length())
{
sb=sb.deleteCharAt(i);
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
return 0;
System.out.println(sb);
}
Irrespective of the exception, this is a very inefficient way to delete chars from the string.
Every time you invoke sb.deleteCharAt(i), it has to shift all of the characters to the right of i along by 1. In the worst case, this has quadratic time complexity.
Instead, it is much more efficient simply to move the characters, and then trim the end:
StringBuilder sb = new StringBuilder(s);
if (!s.isEmpty()) {
int len = 1;
for (int i = 1; i < sb.length(); ++i) {
if (sb.charAt(i) != sb.charAt(len - 1)) {
sb.setCharAt(len++, sb.charAt(i));
}
}
sb.setLength(len);
}
This has linear time complexity.
You can do it a little more directly, too, by operating directly on a char[]:
if (!s.isEmpty()) {
char[] cs = s.toCharArray();
int len = 1; // Start at 1, since the first character isn't equal to the one before it.
for (int i = 1; i < cs.length; ++i) {
if (cs[i] != cs[len-1]) {
cs[len++] = cs[i];
}
}
s = new String(cs, len);
}
while (sb.charAt(i) == sb.charAt(i+1) && i+1<sb.length())
In this line, sb.charAt(i) == sb.charAt(i+1) is evaluated before i+1<sb.length(), which means that you check that a following character exists only after you try to retrieve it.
Swap the two conditions, so that the check is performed before.
The index goes out of bounds because of the i+1
The for(int i = 0; i < sb.length(); i++) makes i vary from 0 to length - 1 due to the less than symbol.
This is correct because a String or N characters will start at index 0 and finish at index N-1.
When you do i+1 in the for loop, when it reaches the last character at index i, i+1 goes out of the character array bounds.
Your problem, as mentioned in the comments, is the while loop - so you should first check i + 1 < sb.length() and then check sb.charAt(i) == sb.charAt(i + 1).
Also - two other things:
Remove the println statement as this makes it not compile
No point returning an int (and hardcoded to 0), so change it to String
Example:
static String alternatingCharacters(String s) {
StringBuilder sb = new StringBuilder(s);
try {
for (int i = 0; i < sb.length(); i++) {
while (i + 1 < sb.length() && sb.charAt(i) == sb.charAt(i + 1)) {
sb = sb.deleteCharAt(i);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
Online Demo
Your problem is that you are iterating till sb.length() and then inside the loop in the while condition you are using :
while (sb.charAt(i) == sb.charAt(i+1) && i+1<sb.length())
And the sentence sb.charAt(i+1) is what icauses the IndexOutOfBoundException because there's no such index in the string.
When the loop reaches the last element, you call sb.charAt(i+1) in the while which is placed before i+1<sb.length() so it will be always executed.
What you need to do is to swap the two conditions in the while loop: while(i+1<sb.length() && sb.charAt(i) == sb.charAt(i+1)).
Index out of bounds is generally caused when you are referencing an index that doesn't exist. Also remember that the index count starts from 0 not 1. On the last loop sb.charAt(i+1) would be 7 + 1 = 8, which doesn't exist since your upper boundary is sb.Length(), to fix this just make your upper boundary for(int i = 0; i < sb.length() - 1; i++)
Loop and delete will cause certainly IndexOutOfBoundsException
StringBuilder sb = new StringBuilder("hello"); // length is 5
sb.deleteCharAt(2); // length is 4
And you still iterate until reaching 5, this will cause the exception
You can use Regex to build a clean solution:
"aaabbcccc".replaceAll("([a-z])\\1{1,}", "$1"); // the result will be abc
I'm looking for the equivalent word in the database by the ContextQuery method, and when a equivalent word is null the program must try to use the next index from words and add it up to the current to make it a two word, if the two word is still null the program will make it a three word looking for the next 2 value, the equivalent is now being printed in console but i have the error IndexOutOfBoundsExpection after running
for (int i = 0; i < words.size(); i++){
temp = QueryWithContext.query(words.get(i));
if((temp == null || temp.isEmpty()) && words.size() >= i+1)
{
QueryWithContext.query(words.get(i)+" "+words.get(i+1));
temp = QueryWithContext.query(words.get(i)+" "+words.get(i+1));
System.out.println("1st if");
if((temp == null || temp.isEmpty()) && words.size() >= i+2)
{
temp = QueryWithContext.query(words.get(i)+" "+words.get(i+1)+" "+words.get(i+2));
}
else
{
temp = words.get(i);
}
}
System.out.println(temp);
if((temp == null || temp.isEmpty()) && words.size() >= i+1)
must be
if((temp == null || temp.isEmpty()) && words.size() > i+1)
otherwise
words.get(i+1)
throws the IndexOutOfBoundsExpection.
The problem is most likely in this line: temp = QueryWithContext.query(words.get(i)+" "+words.get(i+1)+" "+words.get(i+2));. You are looping until i is less than the size of words, so i will range from 0 to n - 1.
The problem is that in your code, you keep going till i + 2 (and previously, i + 1). This is what is most likely causing your error. To fix this, see if you can do the following: for (int i = 0; i < (words.size() - 2); i++){
Alternatively, do as #Uli recommends.
I ve got an issue with the ArrayIndexOutofBound error when trying to determine whether data is heap following the 2i + 1/2 formula child-parent relationship. Do you know how can I resolve the issue?
for (int i = 0; i < array.length; i++)
{
if ((array[i] < array[2*i + 1]) || (array[i] < array[2*i + 2]))
{
bool = false;
....
}
}
I would suggest checking for the boundaries of the array first, and if it contains enough elements, then you can compare them:
if ((array.length >= 2*i + 2)
&& ((array[i] < array[2*i + 1]) || (array[i] < array[2*i + 2])))
{
bool = false;
....
}
Your for-loop guard allows i == array.length -1. But inside the loop, you look for element 2 * i + 2. That's 2 * array.length. That's way beyond the end of the array, and will always throw an excpetion (except when i == 0).
Change your for-loop guard to i < ((array.length / 2) - 1), so that the maximal value of 2 * i + 2 is array.length - 1. Also, ensure you test this both for arrays of even and odd length; I think the logic will work in only one case.
i don't know how to do something specific at the last loop of this for loop:
String msg = "---Player List, Count:" + users.size() + "---" + brln;
for (int i = 0; i < users.size(); i++) {
if((i - 1) == users.size()){
msg += "--::" + users.get(i).name; //Do this at the last loop
return; //returns the void
}
msg += "--::" + users.get(i).name + brln; // do this by default
}
Can you help me get this to work?
Your condition is wrong: instead of (i - 1) == users.size() use (i + 1) == users.size() or i == users.size() - 1.
Basically (i - 1) == users.size() would match the element after the last (which clearly doesn't exist), i.e. for a list of size 5 you'd get (i - 1) == 5 or i == 6.
In the example above (i + 1) == users.size() and i == users.size() - 1 would resolve to (i + 1) == 5 and i == 5 - 1 which both result in i == 4, which is the last index in the list.
Edit: Btw, your loop is still quite odd. You basically seem to add a line break after each but the last element. Why don't you change it to something like this:
String msg = "---Player List, Count:" + users.size() + "---" + brln;
for (int i = 0; i < users.size(); i++) {
if( i > 0){
msg += brln;
}
msg += "--::" + users.get(i).name;
}
This would add a line break before every line except the first. Note how the condition is much easier.
Change this
from:
if((i - 1) == users.size()){
to:
if((i + 1) == users.size()){
What you want in effect is a string of entries separated by a delimiter, where the delimiter is a line break. Use this idiom:
String delimiter = "", result = "";
for (...loop init...) {
result += delimiter;
...append one entry...
delimiter = brln;
}
Other than that, building a large string by creating new string in each iteration is bad for performance as it is an O(n^2) operation. You should prefer a StringBuilder.
If you need last index just use if( i == users.size()-1)
In the example you provide you should use a StringBuilder for string concatenation. Then you only need to loop without asking anything and you can use for-each loop.
StringBuilder msg =new StringBuilder().append("---Player List, Count:").append(users.size()).append("---");
for (User user : users) {
msg.append(brln)
.append("--::").append(user.name)
.append(brln);
}
If you change your code a little, you can avoid a special case:
StringBuilder msg = new StringBuilder("---Player List, Count:" + users.size()
+ "---"); // Note a lack of brln
for (int i = 0; i < users.size(); i++) {
msg.append(brln + "--::" + users.get(i).name);
}
return msg.toString();
Ideally you should use a StringBuilder for concatenating strings in a loop, as I've done above.
(This solution works in your case, since you had a header including a line break. See other solutions for a generic way to insert string X between every occurence but the last in a loop).
you are doing it wrong. Change your line:
if((i - 1) == users.size())
by this one:
if(i == (users.size()-1))
Change your condition to
i == users.size() - 1
Why? In Java (and other languages) the first element in a list is at index 0, and the last element at N-1 (if N is the number of elements currently in the list), so users.size() - 1 is the index of the last element. For example, if there are 10 elements in users list, the last will be at index 9.
Full code:
String msg = "---Player List, Count:" + users.size() + "---" + brln;
for (int i = 0; i < users.size(); i++) {
//if i equals to the last index, do your special handling of the loop
if(i == (users.size() - 1)) {
msg += "--::" + users.get(i).name; //Do this at the last loop
break;
}
msg += "--::" + users.get(i).name + brln; // do this by default
}
Although this might not help you right now (when you don't use Java 8), all this messy code will have an end with Java 8:
// requires Java 8
String msg = users.stream().map(User::name).collect(Collectors.joining(brln));
I have some code that I believe to run in O(n), however when I time it, it seems to run in polynomial time. I'm trying to process ~200,000 records, so I did it in blocks of size MAX_COUNT so I wouldn't run out of heap space. That is, during the processing phase, a few things take place that make the records increase dramatically in size.
I copied in the important parts from my code. I feel like something is going on here that has to do with ArrayLists that I just don't understand.
This might not be the smartest way to go about things, but I don't see why it's taking longer to process each block than the previous. That is, each bock is size 5000 (except the first block), but the 1st block processed takes ~5seconds, and the 20th block processed takes ~25seconds. I would expect them to all take the same amount of time.
// Maximum block size
final int MAX_COUNT = 5000;
// Total number of records in need of processing
int n = records.size();
// the number of blocks to process
int numBlocks = (n / MAX_COUNT) + 1;
if (n % MAX_COUNT == 0) numBlocks--;
// The number of records to process in the block.
int numRecords;
ArrayList<Record> recordBlock = null;
// Iterate backwards through the blocks.
for (int i = numBlocks; i > 0; i--) {
// Make sure we don't process too many records.
if ( (i == 1 && numBlocks = 1 && n % MAX_COUNT != 0) ||
(i == numBlocks && n % MAX_COUNT != 0) )
numRecords = n % MAX_COUNT;
else numRecords = MAX_COUNT;
recordBlock = new ArrayList<Record>();
//EDIT: Fixed loop syntax (typo!)
for (int j = numRecords -1; j >= 0; j--)
recordBlock.add(records.remove(j));
recordBlock = ThreadHelper.processRecords(recordBlock,true,true);
while (recordBlock.size() != 0) {
Record r = recordBlock.remove(recordBlock.size() -1);
// write 'r' to MySQL
}
}
This section
for (int j = numRecords -1; j >= j--)
recordBlock.add(records.remove(j));
will reallocate the backing array behind recordBlock every time the backing array is filled. Rather declare it as
recordBlock = new ArrayList<Record>(numRecords);
Also, the loop syntax is incorrect.
As already mentioned by #mcfinnigan
recordBlock = new ArrayList<Record>(numRecords);
In addition, replace
while (recordBlock.size() != 0) {
Record r = recordBlock.remove(recordBlock.size() -1);
// write 'r' to MySQL
}
by
for (Record r: recordBlock) {// write 'r' to MySQL }
recordBlock.clear();
There is a problem with the for loop adding to the recordBlock.
for (int j = numRecords -1; j >= j--)
recordBlock.add(records.remove(j));
should be
for (int j = numRecords -1; j >= 0; j--)
recordBlock.add(records.remove(j));
If I am not mistaken.
Edit:
Another mistake I found was in your if statement.
if ( (i == 1 && numBlocks = 1 && n % MAX_COUNT != 0) ||
(i == numBlocks && n % MAX_COUNT != 0) )
should be
if ( (i == 1 && numBlocks == 1 && n % MAX_COUNT != 0) ||
(i == numBlocks && n % MAX_COUNT != 0) )
Might I suggest simplifying it to:
if(i == numBlocks && n % MAX_COUNT != 0)
since the first condition is just a special case when i = 1.
if the real code has if and for statements without braces then what you think the code does may not actually be what it does.