For loop different end conditions in the same line? - java

Suppose you want to loop from i=0 to i=n and j=0 to j=m and that m!=n. Is it possible to shorten the following two loops into one?
for(int i=0; i<=n; i++){}
for(int j=0; j<=m; j++){}
To something along
for(int i=0,j=0; i<=n, j<=m; i++, j++){}
In essence I want the loop to say "increment both i and j by one, stop incrementing i if i=n but keep incrementing j if m>n" or the other way around if n>m.
May seem trivial or stupid but I am curious.

Naively, we want to do something like:
for(int i = 0, j = 0; i <= n || j <= m; i = Math.min(n, i+1), j = Math.min(m, j+1))
...but this won't terminate, because the maximum value for i is n and the maximum value for j is m, and one of those will always be true.
The problem is much simpler if you're willing to let (for n < m) i finish at n+1, as we could write:
for(int i = 0, j = 0; i <= n || j <= m; i = Math.min(n+1, i+1), j = Math.min(m+1, j+1))
This is complicated only if you want to keep (for n < m) i = n while j finishes incrementing. The complexity is isolated to getting the loop to terminate at the right time, while still allowing j to finish incrementing.
To get the loop to terminate, we want to increment the larger number one step past its maximum, so that we hit the termination criteria. Since we know at least one of i <= n and j <= m will always be true, let's focus on making both always true, and change our termination criteria to
i <= n && j <= m
In the case where n < m, i will finish incrementing before j, and so we need to let j increment one past its effective maximum in order to violate i <= n && j <= m. A similar condition holds for n > m, but instead, we need to increment i one past n.
Notice, though, that if n == m, we can safely increment both one past their respective limits, and the termination criteria will hit at the same time. The loop below handles any positive input n or m and terminates correctly given your conditons, while allowing the lesser of n or m to become the maximum value for the respective iterator.
for(int i = 0, j = 0, nadj = n + (n >= m ? 1 : 0), madj = m + (m >= n ? 1 : 0)
i <= n && j <= m;
i = Math.min(nadj, i+1), j = Math.min(madj, j+1))
Worth noting, we compute nadj and madj in the first section to avoid recomputing them during every iteration.

Edit
for(int i=0,j=0; i+1<=n || j+1<=m; ){
if(i<n) i++;
if(j<m) j++;
// do stuff here
// keep in mind that i and j starts from 1
}
Fiddle: http://jsfiddle.net/nilgundag/4frCG/
Old Answer:
for(int i=0,j=0; i<=n || j<=m; ){
if(i<=n) i++;
if(j<=m) j++;
// do stuff here
// keep in mind that i and j starts from 1
}

You can use only one iterator i since you increment i and j by 1 every time.
for(int i=0; i<=n || i<=m;i++ ){
if(i<=n) //{do first loop job}
if(i<=m) //{do second loop job}
}

C++:
for (int i=0, j=0; j<=m || i<=n; i+=i<=n, j+=j<=m ){}
JAVA:
for (int i=0, j=0; j<=m || i<=n; i+=(i<=n)?1:0, j+=(j<=m)?1:0 ){}

Related

Kattis time limit exceeded for Java factorial

Within a class Main that attempts to find the last digit of a factorial val, why does
public static void main(String[] args) {
int testcases = sc.nextInt();
for (int i = 0; i < testcases; i++) {
int result = 0;
int val = sc.nextInt();
if (val < 3) {
result = val;
} else {
for (int j = 1; j <= val; j--) {
result *= j;
result %= 10;
}
}
System.out.println(result);
}
}
Take so much longer to compute than the same code except for the difference in this snippet:
for (int j = 1; j <= val; j++) {
result *= j;
result %= 10;
}
I'm aware the second iteration does not provide the right answer, I am curious though as to why it takes so much longer to compute the second as opposed to the first loop.
What the loop code is doing
For loops run a block of code multiple times based on 3 conditions:
The starting value of the loop variable (in your case int j = 1)
The condition in which the loop continues (in your case j <= val - So it will stop once j becomes greater than or equal to val
The way that the loop variable changes with each iteration (in your case either j-- or j++
j-- is the decrement operator. It is the same thing as j = j - 1. j++ on the other hand is the increment operator. It is the same thing as j = j + 1
This means that the loop for (int j = 1; j <= val; j--) will run the block of code with j = 1 and then decrement the value of j. It does this as long as j is less than or equal to val. On the other hand, the loop for (int j = 1; j <= val; j++) runs the block of code and then increments the value of j, which it will do as long as j is less than or equal to val.
So, for j-- the sequence of j values that you have is 1,0,-1,-2... while the sequence of values you have for j++ is 1,2,3,4...
An example run
Let's take an example where val is 10. With j++ your loop will run for 1,2,3,4,5,6,7,8,9,10 and then stop, so it runs 10 iterations. With j-- it will run for 1,0,-1,-2,-3.... As you can see, these values are getting further away from 10, which is the value where the loop will stop. What happens is that the loop just keeps running until your integer overflows. When you get to the lowest possible value of an int, the next iteration of decrementing causes the sign of the number to flip and j become the largest possible integer value, which will be greater than 10 and break the loop. In Java, the standard size of an int is 32 bits, so the smallest integer will be -(2^31-1) which is -2,147,483,648. Therefore, if you run with j--, your loop will run over 2 billion times before stopping which is why it takes so much time to run. .

How does that for loop doesn't goes out of bounds with unidimensional array in JAVA?

Take a look :
int[] v = new int[10];
for (int i = 0; i < v.length; i++) {
for (int j = i + 1; j < v.length; j++) {
if (v[i] > v[j]) {
aux = v[i];
v[i] = v[j];
v[j] = aux;
}
}
}
This works perfecly. But can someone explain how?
How this array DOES NOT goes out of bounds even if I start j with i + 1 ? How does this works?
You have confused the initialization with condition. The syntax for for loop() is-
for(initialization; condition; updation)
{
statement(s)
}
So even if you start j from 1 ( j = i+1 and initial value of i = 0), j will update only till it is equal to the length of the array v i.e., 10. So the moment, j = 10 ( when i = 9), the control will come out of j for loop() and when it will transfer to i for loop(), i will be updated to 10, thus meeting it's condition and moving the control out of i for loop() also.
I think you need to go back to basics on for loops
a for loop can be defined as for(before starting;continue when true;do at end of pass))
So it doesn't matter what your start value is, as soon as j is equal to v.length it will stop. It just does 1 less loop that if you started at i.
Your for loops are made up of a variable to keep track, the condition and the iteration. In your code, the condition of the for loops states that the variable that is keeping track cannot go past the length of v. Therefore, during the sort (because that's what the code is), the inner loop compares all of v's values using j as the index to swap if they meet the if condition. The outer loop is just there to make sure that each index of v is checked and are in the right place.

For loops computation in loop header

int k;
for (int i = 1; i < 10; i++) {
k = 2*i-1;
System.out.print(k+" ");
}
How would I write the above statement with the computation done in the header? I can't seem to figure out the syntax..
So I'm going to answer your question and suggest one minor improvement which moves k into the proper scope of the loop:
for(int i = 1, k = 2*i - 1; i < 10; i++, k = 2*i - 1) {
System.out.println(k+" ");
}
I'm also tending to agree with the comments. You probably should just leave the computation of k inside the loop body for readability's sake. You can still put the declaration of k in the header if k is not needed outside of the scope of the loop.

Worst Case Big O with Java Algorithms

1.
for(i = 0; i < 3; i++){
for(j = 0; j < 10; j++){
print i+j;
}
}
I would assume Big O would be 30 since the most amount of times would be 3*10.
2.
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
print i+j;
}
}
Would be O be n*m?
3.
for(i = 0; i < n; i++){
for(j = 0; j < m; j++){
for(int k = 1; k < 1000; k *= 2){
print i+j+k;
}
}
}
n * m * log base 2 (1000) The Big O is in nlog(n) time
4.
for(i = 0; i < n - 10; i++){
for(j = 0; j < m/2; j++){
print i+j;
}
}
5.
for(i = 0; i < n; i++){
print i;
}
//n and m are some integers
for(j = 1; j < m; j *= 2){
print j;
}
Can someone give me a hand with this if you know Big O. I am looking at these and at a loss. I hope I am posting this in the right location, I find these problems difficult. I appreciate any help.
I think it's important just to point out that Big O notation is all about functions that, given an arbitrary constant, will be considered upper bounds at some point.
O(1)
This is because each loop iterates in a constant amount of time. We would refer to this as O(1) instead of O(30) because the function which is the upper bound is 1 with an arbitrary constant >=30.
O(n*m)
Simply because we have to loop through m iterations n times.
O(n*m)
This is the same as the previous one, only we're throwing in another loop in the middle. Now you can notice that this loop, similar to the first problem, is just a constant time. Therefore, you don't even need to really spend time figuring out how often it loops since it will always be constant - it is O(1) and would be interpreted as O(n*m*1) which we can simply call O(n*m)
O(n*m)
For the outer loop, don't get caught up on the .. - 10 and realize that we can just say that loop runs in O(n). We can ignore that .. - 10 for the same reason we ignored the exact values in the first problem; constants don't really matter. This same principle applies for the m/2 because you can think of m just being manipulated by a constant of 1/2. So we can just call this O(n*m).
T(n) = O(n) + O(lg m) => O(n + lg m)
So there are two components we have to look at here; the first loop and the second loop. The first loop is clearly O(n), so that's no problem. Now the second loop is a little tricky. Basically, you can notice that the iterator j is growing exponentially (notably power of 2's), therefore that loop will be running the inverse of exponentially (logarithmic). So this function runs in O(n + lg m).
Any constant factor can be ignored. O(30) is equal to O(1), which is what one would typically say for 1).
2) Just so.
3) in O(n*m*log_2(1000)), log_2(1000) is constant, so it's O(n*m).
4) O(n-10) is same as O(n). O(m/2) is same as O(m). Thus, O(n*m) again.
5) Trivially O(n).
6) O(log_2(m)).

Going back to the first index after reaching the last one in an array

After my array in the for loop reaches the last index, I get an exception saying that the index is out of bounds. What I wanted is for it to go back to the first index until z is equal to ctr. How can I do that?
My code:
char res;
int ctr = 10
char[] flames = {'F','L','A','M','E','S'};
for(int z = 0; z < ctr-1; z++){
res = (flames[z]);
jLabel1.setText(String.valueOf(res));
}
You need to use an index that is limited to the size of the array. More precisely, and esoterically speaking, you need to map the for-loop iterations {0..9} to the valid indexes for the flame array {0..flames.length()-1}, which are the same, in this case, to {0..5}.
When the loop iterates from 0 to 5, the mapping is trivial. When the loop iterates a 6th time, then you need to map it back to array index 0, when it iterates to the 7th time, you map it to array index 1, and so on.
== Naïve Way ==
for(int z = 0, j = 0; z < ctr-1; z++, j++)
{
if ( j >= flames.length() )
{
j = 0; // reset back to the beginning
}
res = (flames[j]);
jLabel1.setText(String.valueOf(res));
}
== A More Appropriate Way ==
Then you can refine this by realizing flames.length() is an invariant, which you move out of a for-loop.
final int n = flames.length();
for(int z = 0, j = 0; z < ctr-1; z++, j++)
{
if ( j >= n )
{
j = 0; // reset back to the beginning
}
res = (flames[j]);
jLabel1.setText(String.valueOf(res));
}
== How To Do It ==
Now, if you are paying attention, you can see we are simply doing modular arithmetic on the index. So, if we use the modular (%) operator, we can simplify your code:
final int n = flames.length();
for(int z = 0; z < ctr-1; z++)
{
res = (flames[z % n]);
jLabel1.setText(String.valueOf(res));
}
When working with problems like this, think about function mappings, from a Domain (in this case, for loop iterations) to a Range (valid array indices).
More importantly, work it out on paper before you even begin to code. That will take you a long way towards solving these type of elemental problems.
While luis.espinal answer, performance-wise, is better I think you should also take a look into Iterator's as they will give you greater flexibility reading back-and-forth.
Meaning that you could just as easy write FLAMESFLAMES as FLAMESSEMALF, etc...
int ctr = 10;
List<Character> flames = Arrays.asList('F','L','A','M','E','S');
Iterator it = flames.iterator();
for(int z=0; z<ctr-1; z++) {
if(!it.hasNext()) // if you are at the end of the list reset iterator
it = flames.iterator();
System.out.println(it.next().toString()); // use the element
}
Out of curiosity doing this loop 1M times (avg result from 100 samples) takes:
using modulo: 51ms
using iterators: 95ms
using guava cycle iterators: 453ms
Edit:
Cycle iterators, as lbalazscs nicely put it, are even more elegant. They come at a price, and Guava implementation is 4 times slower. You could roll your own implementation, tough.
// guava example of cycle iterators
Iterator<Character> iterator = Iterators.cycle(flames);
for (int z = 0; z < ctr - 1; z++) {
res = iterator.next();
}
You should use % to force the index stay within flames.length so that they make valid index
int len = flames.length;
for(int z = 0; z < ctr-1; z++){
res = (flames[z % len]);
jLabel1.setText(String.valueOf(res));
}
You can try the following:-
char res;
int ctr = 10
char[] flames = {'F','L','A','M','E','S'};
int n = flames.length();
for(int z = 0; z < ctr-1; z++){
res = flames[z %n];
jLabel1.setText(String.valueOf(res));
}
Here is how I would do this:
String flames = "FLAMES";
int ctr = 10;
textLoop(flames.toCharArray(), jLabel1, ctr);
The textLoop method:
void textLoop(Iterable<Character> text, JLabel jLabel, int count){
int idx = 0;
while(true)
for(char ch: text){
jLabel.setText(String.valueOf(ch));
if(++idx < count) return;
}
}
EDIT: found a bug in the code (idx needed to be initialized outside the loop). It's fixed now. I've also refactored it into a seperate function.

Categories