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);
}
Related
I solved a variation of the knapsack problem by backtracking all of the possible solutions. Basically 0 means that item is not in the backpack, 1 means that the item is in the backpack. Cost is the value of all items in the backpack, we are trying to achieve the lowest value possible while having items of every "class". Each time that a combination of all classes is found, I calculate the value of all items and if it's lower than globalBestValue, I save the value. I do this is verify().
Now I'm trying to optimize my recursive backtrack. My idea was to iterate over my array as it's being generated and return the generator if the "cost" of my generated numbers is already higher then my current best-value, therefore the combination currently being generated can't be the new best-value and can be skipped.
However with my optimization, my backtrack is not generating all the values and it actually skips the "best" value I'm trying to find. Could you tell me where the problem is?
private int globalBestValue = Integer.MAX_VALUE;
private int[] arr;
public KnapSack(int numberOfItems) {
arr = new int[numberOfItems];
}
private void generate(int fromIndex) {
int currentCost = 0; // my optimisation starts here
for (int i = 0; i < arr.length; i++) {
if (currentCost > globalBestValue) {
return;
}
if (arr[i] == 1) {
currentCost += allCosts.get(i);
}
} // ends here
if (fromIndex == arr.length) {
verify();
return;
}
for (int i = 0; i <= 1; i++) {
arr[fromIndex] = i;
generate(fromIndex + 1);
}
}
public void verify() {
// skipped the code verifying the arr if it's correct, it's long and not relevant
if (isCorrect == true && currentValue < globalBestValue) {
globalBestValue = currentValue;
}else{
return;
}
}
Pardon my bluntness, but your efforts at optimizing an inefficient algorithm can only be described as polishing the turd. You will not solve a knapsack problem of any decent size by brute force, and early return isn't enough. I have mentioned one approach to writing an efficient program on CodeReview SE; it requires a considerable effort, but you gotta do what you gotta do.
Having said that, I'd recommend you write the arr to console in order to troubleshoot the sequence. It looks like when you go back to the index i-1, the element at i remains set to 1, and you estimate the upper bound instead of the lower one. The following change might work: replace your code
for (int i = 0; i <= 1; i++) {
arr[fromIndex] = i;
generate(fromIndex + 1);
}
with
arr[fromIndex] = 1;
generate(fromIndex + 1);
arr[fromIndex] = 0;
generate(fromIndex + 1);
This turns it into a sort of greedy algorithm: instead of starting with 0000000, you effectively start with 1111111. And obviously, when you store the globalBestValue, you should store the actual data which gives it. But the main advice is: when your algorithm behaves weirdly, tracing is your friend.
So I decided to go to codewars to just brush up a little bit on java and I have this problem to solve:
You are given an array (which will have a length of at least 3, but could be very large) containing integers. The array is either entirely comprised of odd integers or entirely comprised of even integers except for a single integer N. Write a method that takes the array as an argument and returns this "outlier" N.
Here are my test cases:
public class OutlierTest{
#Test
public void testExample() {
int[] exampleTest1 = {2,6,8,-10,3};
int[] exampleTest2 = {206847684,1056521,7,17,1901,21104421,7,1,35521,1,7781};
int[] exampleTest3 = {Integer.MAX_VALUE, 0, 1};
assertEquals(3, FindOutlier.find(exampleTest1));
assertEquals(206847684, FindOutlier.find(exampleTest2));
assertEquals(0, FindOutlier.find(exampleTest3));
}}
And here is the code i used to solve the problem:
public class FindOutlier{
static int find(int[] integers){
int numerOfOdds = 0;
int numberOfEvens = 0;
int integerOutlier;
for(int i = 0; i < integers.length ;i++){
if ( integers[i]%2 == 0){
numberOfEvens++;
}else{
numerOfOdds++;
}
}
if ( numberOfEvens > numerOfOdds){
integerOutlier = 1;
}else{
integerOutlier = 0;
}
for(int i = 0; i < integers.length; i++){
if ((integers[i]%2) == integerOutlier){
return integers[i];
}
}
return 0;
}}
Essentially what the code does is loops through the array to find the outlying parity. Then loops again to determine the outlying integer.
This code passes all of its testcases. However, when I try to attempt to submit the code it tells me that it is expecting -3 but got 0.
Can anyone help me find the fault in my logic here?
It's kinda frustrating because it doesn't tell me what the array its testing for so I cant trace my code to find the fault.
Excuse me for the typos and if they code isn't the most efficient, I probably would have used ArrayLists, but it seems like CodeWars doesn't allow for ArrayLists...
Well, your math has a bug: -3 % 2 == -1, so when a negative odd number is the outlier it fails. Change your second loop to
for(int i = 0; i < integers.length; i++){
if (Math.abs(integers[i]%2) == integerOutlier){
return integers[i];
}
}
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;
}
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!
I am trying to write quick sort in java. But getting a stack over flow error for very small set of inputs. In the createArray function I am taking input by the Scanner object.
Please somebody help me in this.
public class quickSort {
static int[] ar;
int number;
public static void main(String args[]) {
CreatingArray ca = new CreatingArray();
ar = ca.createArray();
ca.printArray(ar);
int len = ar.length;
sort(0,(len-1));
System.out.println("");
System.out.println("Array after QuickSort:");
ca.printArray(ar);
}
public static void sort(int l,int h) {
int i=l;
int j=h;
int temp =0;
int pivot = ar[(l + (l+h)/2)];
while(i <= j) {
while(ar[i] < pivot) {
i++;
}
while(ar[j] > pivot) {
j--;
}
if (i<=j) {
temp = ar[i];
ar[i] = ar[j];
ar[j] = temp;
i++;
j--;
}
}
if(l<j){
sort(l,j);
}
if(i<h) {
sort(i,h);
}
}
}
int pivot = ar[(l + (l+h)/2)];
This line is wrong. It only gets the center point when l == 0. If, say, l == 4 && h == 7 (e.g. the upper half of an 8-element array), you get 4 + (4+7)/2 which is 9 and thus outside the bounds. You really want l + (h-l+1)/2.
The first thing that can happen because of this is ArrayIndexOutOfBoundsException, but you never get that because you always recurse on the lower partition first and run into the second problem. Swap the two ifs at the end of the function to see this in action.
The second thing that can happen is that, because pivot is not actually an element in the range [i, j], the element search at the start of the loop can go crazy. In particular, pivot could be a very small value that is smaller than any in the range. The i search will terminate immediately (leaving i == l the way it started), while the j search will run way beyond i, which means the if won't be entered either, i still doesn't change, and the main loop terminates. Because i is unchanged, i<h is still true (assuming l<h was), and you enter the recursive call with exactly the same arguments you just had, which means the next call will do exactly the same thing as the current one, ending in infinite recursion.
I think your recursive calls don't end... debug your code with very small input - say 3 numbers... check when and how sort() is being called..