Java inner and outer loop confusion? - java

I have a function isEvenSubset(12, 18) which returns 1 if all the even factors of 18 lies in even factors of 12. This function return 1 for 12 and 18.
18=2,6(even factors)
12=2,4,6(even factors)
My code for this is given below:
public static void main(String[] args) {
System.out.println(isEvenSubset(12, 18));
}
static int isEvenSubset(int m, int n) {
int a=0;
int factn=0;
for (int i = 1; i <n; i++) {
int factm=0;
for (int j = 1; j <m; j++) {
if(n%i==0&&i%2==0&&factm!=0){
factn=i;
System.out.println(factn+" "+factm);
if(factn==factm){
a=1;
}
}
if(m%j==0&&j%2==0){
factm=j;
}
}
}
return a;
}
The result is not as expected. I am confused where in the code should I check factn==factm. Can somebody please give me some hint if using inner and outer loop is suitable here or should I look for any other approach.

You do not need a nested loop here at all and are overcomplicating a simple thing. You want to know if all even factors of a number n are a subset of the even factors of another number m. Approach it like this:
Go through all even numbers (2, 4, 6, 8, 10, ...) up to m.
Check if your n can be divided by it.
If yes, check if m can not be divided by it. If that's the case, return false.
And you are done. It's a simple 3 step algorithm. In code it could look like this:
for (int f = 2; f < m; f += 2)
{
if (n % f == 0 && m % f != 0)
{
return false;
}
}
return true;
This is definitely not a fully optimized version and probably not even close to it. There are even simpler solutions to solve your problem. However it's still far less complex than what you attempted.

Your algorithm has an O(n^2) time complexity, which is very bad.
I'd make a function which calculates even factors of a number and returns them in an array.
So your main should call twice that function, returning two arrays. Then you should check whether all the numbers of m's array are contained within n's. That time complexity would be O(n).

You confuse yourself cause your algorithm is to much complicated.
Just loop for all even number between 0 and the first number (here 18). For each one check if it divides the first number (18). If it does, check if it also divides the second number (12). If one that divide the first does not divide the second, exit and return 0 (or false). If you reach the end of the loop, all even divider of the first number also divides the second number so return 1 (or true).
static int isEvenSubset(int firstNumber, int secondNumber) {
for (int i=2; i<firstNumber; i+=2) {
if(firstNumber%i == 0) {
if(secondNumber%i !=0) {
return false;
}
}
}
return true;
}

Related

how to use value of a variable that was calculated inside a loop in java

`
public static int Digits(int n){
int nbr=0,count=0;
while (nbr!=0){
nbr= nbr/10;
count++;
}
return count;}`
I'm sorry if this question seems silly but I've never taken any java outside university and I have an assignment. The exercise asks to state whether the number of digits of an integer is smaller, equal, or bigger than the number of digits of another integer using method. For this purpose, I used a while loop in the method which tells me the count of the number of digits of a given integer.
I know that I have to declare a variable outside the loop if I want to use it outside the loop.However, I have to initialize it outside the loop so I can use it inside the loop. But I want the value of the count after it has been calculated inside the loop and I'm not able to do this although I tried really hard and searched for answers but didn't find any.
First of all you need to delete count = 0 inside the loop because it will always be 0. Second thing is that your while condition (nbr! = 0) is never true because in declaration you set it to 0
Below function return number of digits in number passed as argument
public static int Digits(int n)
{
int count = 0;
while(n != 0)
{
count++;
n /= 10;
}
return count;
}
There are couples of fixes/improvements needed in this code.
Digits variable is not used.
nbr is always 0 and not assigned the value of n.
On each iteration, count is reset to 0.
It doesn't consider 0, it is digit of one length.
public static int countOfDigits(int n) {
if (n == 0) {
return 1;
}
int count = 0;
while (n != 0) {
n = n / 10;
count++;
}
return count;
}

How to know the fewest numbers we should add to get a full array

recently I met a question like this:
Assume you have an int N, and you also have an int[] and each element in this array can only be used once time. And we need to design an algorithm to get 1 to N by adding those numbers and finally return the least numbers we need to add.
For example:
N = 6, array is [1,3]
1 : we already have.
2 : we need to add it to the array.
3 : we can get it by doing 1 + 2.
4: 1 + 3.
5 : 2 + 3.
6 : 1 + 2 + 3.
So we just need to add 2 to our array and finally we return 1.
I am thinking of solving this by using DFS.
Do you have some better solutions? Thanks!
Here's an explanation for why the solution the OP posted works (the algorithm, briefly, is to traverse the sorted existing elements, keep an accumulating sum of the preceding existing elements and add an element to the array and sum if it does not exist and exceeds the current sum):
The loop tests in order each element that must be formed and sums the preceding elements. It alerts us if there is an element needed that's greater than the current sum. If you think about it, it's really simple! How could we make the element when we've already used all the preceding elements, which is what the sum represents!
In contrast, how do we know that all the intermediate elements will be able to be formed when the sum is larger than the current element? For example, consider n = 7, a = {}:
The function adds {1,2,4...}
So we are up to 4 and we know 1,2,3,4 are covered,
each can be formed from equal or lower numbers in the array.
At any point, m, in the traversal, we know for sure that
X0 + X1 ... + Xm make the largest number we can make, call it Y.
But we also know that we can make 1,2,3...Xm
Therefore, we can make Y-1, Y-2, Y-3...Y-Xm
(In this example: Xm = 4; Y = 1+2+4 = 7; Y-1 = 6; Y-2 = 5)
Q.E.D.
I don't know if this is a good solution or not:
I would create a second array (boolean array) remembering all numbers I can calculate.
Then I would write a method simulating the adding of a number to the array. (In your example the 1, 3 and 2 are added to the array).
The boolean array will be updated to always remember which values (numbers) can be calculated with the added numbers.
After calling the add method on the initial array values, you test for every Number x ( 1 <= x <= N ) if x can be calculated. If not call the add method for x.
since my explanation is no good I will add (untested) Java code:
static int[] arr = {3,5};
static int N = 20;
//An Array remembering which values can be calculated so far
static boolean[] canCalculate = new boolean[N];
//Calculate how many numbers must be added to the array ( Runtime O(N^2) )
public static int method(){
//Preperation (adding every given Number in the array)
for(int i=0; i<arr.length; i++){
addNumber(arr[i]);
}
//The number of elements added to the initial array
int result = 0;
//Adding (and counting) the missing numbers (Runtime O(N^2) )
for(int i=1; i<=N; i++){
if( !canCalculate[i-1] ){
addNumber(i);
result++;
}
}
return result;
}
//This Method is called whenever a new number is added to your array
//runtime O(N)
public static void addNumber( int number ){
System.out.println("Add Number: "+(number));
boolean[] newarray = new boolean[N];
newarray[number-1] = true;
//Test which values can be calculated after adding this number
//And update the array
for(int i=1; i<=N; i++){
if( canCalculate[i-1] ){
newarray[i-1] = true;
if( i + number <= N ){
newarray[i+number-1] = true;
}
}
}
canCalculate = newarray;
}
Edit: Tested the code and changed some errors (but rachel's solution seems to be better anyway)
It is a famous problem from dynamic programming. You can refer to complete solution here https://www.youtube.com/watch?v=s6FhG--P7z0
I just found a possible solution like this
public static int getNum(int n, int[] a) {
ArrayList<Integer> output = new ArrayList<Integer>();
Arrays.sort(a);
int sum = 0;
int i = 0;
while(true) {
if (i >= a.length || a[i] > sum + 1) {
output.add(sum + 1);
sum += sum + 1;
} else {
sum += a[i];
i++;
}
if (sum >= n) {
break;
}
}
return output.size();
};
And I test some cases and it looks correct.
But the one who write this didn't give us any hints and I am really confused with this one. Can anybody come up with some explanations ? Thanks!

How to recall a function, Sieve of Eratosthenes

I'm trying to write code that will work out prime numbers using the sieve of Eratosthenes. I have to include a function that will take in a number and cross of all of the multiples of that number. For testing I set the first number to be 2 and the second as 3. It works for the first number but never for the second(no matter the order of the numbers i.e if I put 3 into the function first). I know there are other completed sieve of Eratosthenes out there but I wanted to try and do it in the way that I thought of first.
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
System.out.println("Which number would you like to calculate up to?");
int n = input.nextInt();
input.close();
int x = 0;
int newNumber = 2;
int numbers[] = new int[n];
while(newNumber <= n){
numbers[x] = newNumber;
x++;
newNumber++;
}
int currentNumber = 2;
int finalNumber[] = markOfMultiples(n, numbers, currentNumber);
for(int y = 0;y < n-1;y++){
System.out.print(finalNumber[y] + ", ");
}
currentNumber = 3;
int secondNumber[] = markOfMultiples(n, numbers, currentNumber);
for(int y = 0;y < n-1;y++){
System.out.println(secondNumber[y]);
}
}
public static int[] markOfMultiples(int n, int numbers[], int currentNumber){
int originalNumber = currentNumber;
while(currentNumber<n){
currentNumber = currentNumber + originalNumber;
int count2 = 0;
while(currentNumber != numbers[count2] && currentNumber<=n && count2<n){
count2++;
}
numbers[count2] = 0;
}
return numbers;
}
The error I'm getting is: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 20
at sieveOfEratosthenes.sieveOfEratosthenes.markOfMultiples(sieveOfEratosthenes.java:46)
at sieveOfEratosthenes.sieveOfEratosthenes.main(sieveOfEratosthenes.java:28)
Line 28 is when I recall the function:int secondNumber[] = markOfMultiples(n, numbers, currentNumber);
And line 46 is while(currentNumber != numbers[count2] && currentNumber<=n && count2<20){
Any help would be much appreciated. How do I keep on calling the function?
p.s. Please excuse the variable names as I'll be changing them when I get the program working.
If you want to get this approach working, you can do the fix advised by #Thierry to check count2 < n first in your while loop and then also surround the line
numbers[count2] = 0
with an if clause to check count2 is not beyond the end of the index. e.g.
if (count2 < n) {
numbers[count2] = 0;
}
Your final challenge is how you call your markOfMultiples() function enough times when n gets a bit larger. It's not a problem with your fundamental approach - you can definitely do it and your approach will work well and have acceptable performance for low-ish numbers (say up to 10000).
However
I realise this is an assignment and you want to do it your way, but there are a few features of your approach which you might want to consider - maybe after you've got it working.
Readability - is it going to be easy for someone looking at (marking) your code to understand what it's doing and verify that it will do the right thing for all values of n?
Try not to repeat yourself - for instance consider where you fill your numbers array:
while(newNumber <= n){
numbers[x] = newNumber;
x++;
newNumber++;
}
Will x ever be different to newNumber? Did you need both variables? This sort or repetition occurs elsewhere in your code - the principle to stick to is known as DRY (Don't Repeat Yourself)
Is there an easier way to move the index on originalNumber places in your markOfMultiples() method? (HINT: yes, there is)
Do you really need the actual numbers in the numbers[] array? You're going to end up with a lot of zeros and the primes left as integer values if you work out how to call your markOfMultiples repeatedly for high values of n. Would an array of 1s and 0s (or trues and falses) be enough if you used the array index to give you the prime number?
You need to test if count2 < n BEFORE access to numbers[count2]:
while(count2 < n && currentNumber != numbers[count2] && currentNumber<= n){
count2++;
}

Converting an Iterative Method to a Recursive one (Java)

For my discrete structures class at uni, I need to write a method that solves the formulas below:
 
s[0] = 1
s[n-1] = s[n-2] + n for all n >= 2
Unfortunately, I've not implemented many recursive methods before, so I don't really know what I'm doing. Things just aren't "clicking" for me like they normally do.
I'd appreciate help in any way possible, but I'd rather fully understand this, rather than just copypaste someone else's work.
A basic example for what this method should accomplish if n = 8...
1 + 2 = 3,
3 + 3 = 6,
6 + 4 = 10,
10 + 5 = 15,
15 + 6 = 21,
21 + 7 = 28,
28 + 8 = 36, our answer.
I've written a method to solve this NON-recursively (shown below), so I do understand the math behind it.
public static int sequenceNonRecursive(int n){
int[] s = new int[n];
s[0] = 1;
if(n >= 2){
for(int i = 1; i < n; i++){
s[i] = s[i-1] + i + 1;
}
}
return s[n-1];
}
EDIT: I solved it. Thanks for your help, everyone! Look below for my answer.
The recurrence is defined a little oddly. I would rewrite it:
S0 = 1
Si = Si-1 + i + 1 — ∀ i > 0
The routine can be simplified to not use an array:
public static int sequenceNonRecursive (int n) {
int S_0 = 1; // 0th term is 1
int S_i = S_0; // S_i starts at S_0
for(int i = 1; i <= n; i++) {
int S_i_minus_1 = S_i; // use previous result to calculate next
S_i = S_i_minus_1 + i + 1; // next is previous added with index plus 1
}
return S_i;
}
Any loop can be converted into an equivalent recursive routine. The trick is that local variables turn into function parameters for the recursive routine and the loop control turns into an if. If the condition is false, the function returns with the result. Otherwise, the function does the computation as if it is the loop body, and then uses recursion to iterate.
As an illustration, given the function:
public static int someFunction (int n) {
int result = DEFAULT_RESULT;
for (int i = 0; i < n; ++i) {
result = UPDATE_RESULT(i, n, result);
}
return result;
}
Then, the body of this function can be changed to call a recursive function instead:
public static int someFunction (int n) {
return someFunctionWithRecursion(n, 0, DEFAULT_RESULT);
}
Notice how the initial values of local variables have been converted into parameters to the recursive routine. So, the recursive routine itself may look like:
public static int someFunctionWithRecursion (int n, int i, int result) {
if (! (i < n)) {
return result;
}
result = UPDATE_RESULT(i, n, result);
return someFunctionWithRecursion(n, i+1, result);
}
Notice that in the recursive call, the result has been updated, and the control variable i has been incremented, just as an iteration would have done in the original for() loop version of the code.
As an aside: The recurrence you are working on actually has a closed form:
Sn = (½)(n+1)(n+2)
It's actually easier. Imagine that your method works for all n's and that unless n is zero (the base case) you use
sequenceRecursive(n-1)
to get the value of the previous number and just expect it to work. (and it will)
Under the hood it will recurse down to the base case and build up the value as the calls return.
Recursion is like breaking down the original problem into sub problems and trying to solve them. To start with you need to figure out the base case(which in your case is n=0). Now you can move ahead and see how you can handle cases where n > 0 by breaking it down to the base case. Creating the sequence for n then n-1 then n-2 and so on till you reach the base case is the key to solve this problem recursively.
Structure your code something like this (just giving hints, leaving you to figure out the rest of the problem):
public static int sequenceRecursive(int n){
if( n == 0 )
//return something....
else
//return something else, which recursively relies on previous values of sequenceRecursive()
}
Let's first add 1 to all n's in your second equation: (if we increase them, we need to decrease the range, seeing that it's correct should be trivial)
s[0] = 1
s[n] = s[n-1] + (n+1) for all n >= 1
Why do we want to do this?
In short, the function definition is sequence(int n), not sequence(int n-1).
Here s[i] just corresponds to calling your function with input parameter i.
And the basic idea for the code:
public static int sequence(int n){
if (/* base case */)
// return value for base case
else
// return other case, includes calling sequence(x) for some x
}
Hope that gives you enough to work from.
I got it, guys. Thank ALL of you for your help! I can't believe how stupidly simple this was. As soon as I figured it out, I gave myself a forceful facepalm. I'm pretty sure I understand recursion now.
public static int sequenceRecursive(int n){
if( n == 0 )
return 0;
else
return n + sequenceRecursive(n-1);
}

Combination of element in array, for getting factors of number

I want a combination algorithm,...to multiple the elements in the array, to every other element but itself....
please help me to combine eg:: {1,2,3,4,5,6}
output:: 1*2,1*3....1*6, 1*2*3 !*2*4.......1*2*3*4*5*6.......5*6
code removed it was irrelevant to my logical requirement of question...
I believe this is what you are looking for:
//This method return a list of lists, where each "inner list" contains as
//its first number the number for which the factors are being found, and
//every other number is a factor.
//It takes an array of all the numbers whose factor you wish to find
public List<List<Integer>> getAllFactors(int[] toCalculate){
List<List<Integer>> toReturn = new ArrayList<List<Integer>>();
List<Integer> factors;
for(int i = 0; i < toCalculate.length; i++){
factors = new ArrayList<Integer>();
factors.add(toCalculate[i]); //add the number whose factors will be calculated
//the square root is used because it is the largest number you can divide by without getting "overlap"
for(int j = 1; j <= Math.sqrt(toCalculate[i]); j++){
if(toCalculate[i]%j==0){ //if it divides evenly, add it
factors.add(j);
factors.add((Integer)toCalculate[i]/j); //also add its "partner" number
}
}
toReturn.add(factors);
}
return toReturn;
}
I put in class Test... Here is my testing method:
public static void main(String[] args){
Test t = new Test();
List<List<Integer>> blah = t.getAllFactors(new int[]{10, 12, 1, 5});
for(List<Integer> i: blah)
System.out.println(Arrays.toString(i.toArray(new Integer[i.size()])));
}
I realized that this wasn't what the question asked for... I think... I can't really tell...
Anyway, I wrote an alternative method:
public List<Integer> getAllFactors(int number){
List<Integer> factors = new ArrayList<Integer>();
for(int i = 2; i <= Math.sqrt(number); i++){
if(number%i==0){
factors.add(number);
factors.addAll(getAllFactors(i));
factors.addAll(getAllFactors(number/i));
}
}
if(factors.isEmpty())
factors.add(number);
return factors;
}
But then I realized that might not be what you want either. The fact is, I actually have no fricking clue what you are looking for, I can't understand your post. I have just been trying to glean info from the comments.
Why not just declare arr as a Set from the start?
Set<Integer> arr = new LinkedHashSet<Integer>();
And leave it at that. You never want duplicates, and if order is important, a LinkedHashSet preserves insertion order.
First, finding factors. Here is a fragment from my own code. It builds a list of factors of target in an ArrayList called factors. As each factor is found it is recorded once and divided out as many time as is needed. The upper limit is then reduced accordingly. The variable residue holds the unfactored portion of target.
int trialFactor = 0;
int residue = target;
limit = iSqrt(residue);
while (trialFactor < limit) {
trialFactor = nextPrime(trialFactor);
if (residue % trialFactor == 0) {
factors.add(trialFactor);
do {
// Remove repeated factors.
residue /= trialFactor;
} while (residue % trialFactor == 0);
limit = iSqrt(residue);
}
}
// Record largest factor, if present.
if (residue > 1) { factors.add(residue); }
There are two of my own functions used:
int nextPrime(int) which returns the next highest prime.
int iSqrt(int) which returns the integer square root; iSqrt(10) returns 3.
Now for the second part of your question, combinations. You have a group of items and you want all the possible combinations. If there are n items then just iterate through all the numbers 0 to (2^n) - 1. That will give you all the bit patterns from 000 ... 000 to 111 ... 111. For each position in your group a '0' means not to include it in your output while a '1' means to include it.
So, given your {1,2,3,4,5,6} example, you need numbers from 0 to 2^6 - 1 = 63. Take an example, 45 is 101101 in binary, so your output for 45 is {1,3,4,6}.

Categories