pretty simple question:
Given an array, find all subsets which sum to value k
I am trying to do this in Java and seem to have found a solution which solves it in O(n^2) time. Is this solution a correct O(n^2) implementation?
#Test
public void testFindAllSubsets() {
int[] array = {4,6,1,6,2,1,7};
int k=7;
// here the algorithm starts
for(int i = 0; i < array.length;i++){
// now work backwords
int sum = array[i];
List<Integer> subset = new ArrayList<Integer>();
subset.add(array[i]);
for(int j = array.length -1; j > i && sum < k; j--){
int newSum = sum + array[j];
// if the sum is greater, than ditch this subset
if(newSum <= k){
subset.add(array[j]);
sum = newSum;
}
}
// we won't always find a subset, but if we do print it out
if(sum == k){
System.out.print("{");
System.out.print(subset.get(0));
for(int l = 1; l < subset.size(); l++){
System.out.print(","+subset.get(l));
}
System.out.print("}");
System.out.println();
}
}
}
I have tried it with various examples and have not found any that seem to break it. However, when I have searched online, this does not appear to be the common solution to the problem, and many solution claim this problem is O(2^n).
P.S.
This is not a homework question, I'm a brogrammer with a job trying to work on my Comp Sci fundamentals in Java. Thanks!
No this is not correct.Take this simple example
Your array is 4,6,1,2,3,1 and target sum is 7 then in your logic it
would only find (4,3) (6,1) (1,2,3,1) your code would miss (4,2,1), (4,3).
I would refer to go through wiki
An elegant solution is to simply think of a subset as each member answering the question "Am I in or not?" So essentially each can answer yes/no, so you have 2N subsets(including the empty subset). The most natural way to code this up is to recurse through each element and do one of the following:
Pick it
Skip it
Thus the time complexity is O(2N) simply because you have so many answers possible in the worst case.
Related
So I have been learning Dynamic Programming (DP) recently and when I came upon the following problem, I decided to use DP but since I'm a beginner in algorithms, I am not sure if this is a valid example of DP or not.
Problem:
Given an array nums. We define a running sum of an array as runningSum[i] = sum(nums[0]…nums[i]). Return the running sum of nums.
Example 1:
Input: nums = [1,2,3,4]
Output: [1,3,6,10]
Explanation: Running sum is obtained as follows: [1, 1+2, 1+2+3, 1+2+3+4].
This is my "DP" solution:
class Solution {
public int[] runningSum(int[] nums) {
int[] arr = new int[nums.length];
int sum = 0;
for(int i = 0; i < nums.length; i++){
arr[i] = nums[i] + sum;
sum += nums[i];
}
return arr;
}
}
According to Wikipedia:
There are two key attributes that a problem must have in order for dynamic programming to be applicable: optimal substructure and overlapping sub-problems. If a problem can be solved by combining optimal solutions to non-overlapping sub-problems, the strategy is called "divide and conquer" instead. This is why merge sort and quick sort are not classified as dynamic programming problems.
In your case, you are implementing following strategy:
sum_all(array) = array[0] + sum_all(array[1..])
At each step there is only one subproblem, and that means there is no overlap of the subproblems. Indeed, this is a degenerate form of divide and conquer.
I think the main thing why I'm hesitant to call your algorithm DP is absence of optimization. Certainly, your task can be divided to smaller subtasks and result for size n assembled from result for size n-1. But DP is optimization strategy. I cannot see anything to be optimized in your task.
Example 1:
Input: nums = [1,2,3,4]
Output: [1,3,6,10]
Explanation: Running sum is obtained as follows: [1, 1+2, 1+2+3, 1+2+3+4].
Just use this:
Create a prefix array and every element of this array is the sum of previous element and element of original array
int[] P = new int[4];
for (int i = 0; i < 4; i++)
{
if (i == 0) P[i] = nums[i];
else P[i] = P[i-1] + nums[i];
}
Also this is good to use
vector<int> P; // running sum list
vector<int> nums = {1,2,3,4}; // given input
int sum = 0; // sum at any running position
for(auto x : nums)
{
P.push_back(sum+x);
sum += x;
}
I'm studying sorting algorithms, including selection sort, so i decided to write a method and it works fine, but when i checked the book it had 2 variables so i checked it and found that it's using a variable to store the current index and the other as temporary to swap
while mine had only the temporary variable that also stored the initial value in the index as the lowest, then compared it to the other values in the array and swapped if a larger value was found.
Here's my code:
public static void selectionSort(int[] arr){
int lowest;
for(int i = 0; i < arr.length - 1; i++){
lowest = arr[i];
for(int j = i+1; j<arr.length; j++){
if(arr[j]<lowest){
lowest = arr[j];
arr[j] = arr[i];
arr[i] = lowest;
}
}
}
}
and Here's the book's
public static void selectionSort(int[] list){
int min;
int temp;
for(int i = 0; i < list.length - 1; i++) {
min = i;
for(int j = i + 1; j < list.length; j++)
if( list[j] < list[min] )
min = j;
temp = list[i];
list[i] = list[min];
list[min] = temp;
}
}
so I looked on the web and all of them follow the same way as the book, so is my code bad or slower, or it is not considered Selection sort ?
sorry for any english mistakes :P
So, the original code works like this:
Start with the first element of the array
Find the smallest number in the array
Swap the two numbers
Repeat the process Until You reach the end of the list
While Yours does this:
Start with the first element of the array
For each element smaller than the current Swap the two numbers
Replace the lowest number with the swapped
Repeat the process
The result should be the same, but probably You are swapping more numbers than the first one. This probably will make it a little bit slower than the original.
Actually it kinda looks like the insertion sort now, so basically You are swapping the elements with all that are bigger than the one You have.
It looks like you're doing a lot more swaps in the nested for loop.
What happens if you do a sort of [4,3,2,1]? I think you'll have more swap operations than the actual selectionSort.
I'm not sure if your code is bad or slower.
SelectionSort is known to be correct, but it isn't fast either.
I am trying to write a method called permutations. Basically, I want it to take in an integer and then return all of the permutations of the numbers from 0 to x -1. I realize this should return an array of arrays. However I am struggling to actually implement this. Can someone help me think about this in a better way? I am coding this in java. I realize this will probably be a recursion problem but other than that I am at a loss.
I thought about having two methods, one that takes in the integer and makes the first array from 0 - x-1. Then another method that takes in an array and some integer "start". This way the integer at index start will not change, but there will be swapping with the other numbers. This would be inside of a for loop so that the "start" position will change throughout the array. The only hint I have for this was that my for loop is going to recursively call the method. However I am having trouble thinking about how to actually implement this and the algorithm for the swapping.
Can someone tell me if I am thinking about this right and if they have any ideas or hints to give me? I do not have code to share since I have been white boarding the majority of my thoughts for this.
Permutation can be solved in a typical Backtrack algorithm in which we have to traverse all possibilities in the state space. Backtrack is a very important algorithm and my suggestion is that you have a look at it(which is usually in a recursion form) and try to master the basic idea of it, rather than trying to solving permuation problem in your own way.
Basically to find a permutaion we have to walk n steps(setting one bit is one step), after we choose one bit for each step, we have a permutation, so we have one possible solution(say, it is 1,2,3,4,5,6). After that, we backtrack to the second last bit, note that we chosed 5 in our first solution, but we can have another choice 6, after that we only have one choice for the last bit which is 5. For other solutions we continue to backtrack to the third last bit, fourth last bit..., and so on. That is the reason why backtrack is named.
You can compare backtrack with DFS, or traveral algorithm on a binary tree. They are in many places very similar with each other.
Below is my solution for this problem in which the result is an arrayList and permutaion is given according to 1...n instead of 0...n-1, but the thought in it is exactly the same.
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> permutations=new ArrayList();
backtrack(permutations,new ArrayList<Integer>(),nums);
return permutations;
}
private void backtrack(List<List<Integer>> permutations,List<Integer> tempList,int[] nums){
if(tempList.size()==nums.length){
permutations.add(new ArrayList<Integer>(tempList));
return;
}
for(int i=0;i<nums.length;i++){
if(tempList.contains(nums[i])){
continue;
}
tempList.add(nums[i]);
backtrack(permutations,tempList,nums);
tempList.remove(tempList.size()-1);
}
}
}
If I understood you correctly,this is smt you want?
public class MyClass_3928{
static List<String> listOfAllArrays = new ArrayList<>();
public static void calculate(int[] list, int n) {
if (n == 1) {
listOfAllArrays.add(Arrays.toString(list));
} else {
for (int i = 0; i < n; i++) {
calculate(list, n - 1);
int j = (n % 2 == 0) ? i : 0;
int t = list[n - 1];
list[n - 1] = list[j];
list[j] = t;
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("How many numbers would you like to permute?");
int numbers = Integer.valueOf(scanner.nextLine());
int[] numbersArray = new int[numbers-1];
System.out.println("Those numbers are");
for (int i = 0; i < numbers-1; i++) {
numbersArray[i] = i+1;
}
calculate(numbersArray, numbersArray.length);
for (int i = 0; i < listOfAllArrays.size(); i++) {
System.out.println(listOfAllArrays.get(i));
}
}
So I was working on this sorting algorithm in java, and was wondering if anybody has seen anything like this before. Specifically, this algorithm is meant to sort very large lists with a very small range of numbers. If you have seen that or have any suggestions to enhance the algorithm, can you say something about that below? I have the code here:
public static int[] sort(int[] nums)
{
int lowest = Integer.MAX_VALUE;
for (int n : nums)
{
if (n < lowest)
lowest = n;
}
int index = 0;
int down = 0;
while (index < nums.length)
{
for (int i = index; i < nums.length; i++)
{
if (nums[i] == lowest)
{
int temp = nums[i] + down;
nums[i] = nums[index];
nums[index] = temp;
index++;
}
else
nums[i]--;
}
down++;
}
return nums;
}
If I'm not mistaken, that is your standard-issue BubbleSort. It's simple to implement but has poor performance: O(n^2). Notice the two nested loops: as the size of the array increases, the runtime of the algorithm will increase exponentially.
It's named Bubble Sort because the smallest values will "bubble" to the front of the array, one at a time. You can read more about it on Wikipedia.
So the algorithm seems to work but it does a lot of unnecessary work in the process.
Basically you are throwing in the necessity to subtract from a number x times before you add x back and try and swap it where x is the difference between the number and the lowest number in the array. Take [99, 1] for example. With your algorithm you would update the array to [98, 1] in the first for loop iteration and then the next you would make the swap [1, 98] then you have to make 97 more iterations to bring your down variable up to 98 and your array to [1,1] state then you add 98 to it and swap it with itself. Its an interesting technique for sure but its not very efficient.
The best algorithm for any given job really depends on what you know about your data. Look into other sorting algorithms to get a feel for what they do and why they do it. Make sure that you walk through the algorithm you make and try to get rid of unnecessary steps.
To enhance the algorithm first I would get rid of finding the lowest in the set and remove the addition and subtraction steps. If you know that your numbers will all be integers in a given range look into bucket sorting otherwise you can try merge or quicksort algorithms.
I want to find The number of ways to divide an array into 3 contiguous parts such that the sum of the three parts is equal
-10^9 <= A[i] <= 10^9
My approach:
Taking Input and Checking for Base Case:
for(int i=0;i<n;i++){
a[i]= in.nextLong();
sum+=a[i];
}
if(sum%3!=0)System.out.println("0");
If The answer is not above Then Forming the Prefix and Suffix Sum.
for(int i=1;i<=n-2;i++){
xx+=a[i-1];
if(xx==sum/3){
dp[i]=1;
}
}
Suffix Sum and Updating the Binary Index Tree:
for(int i=n ;i>=3;i--){
xx+=a[i-1];
if(xx==sum/3){
update(i, 1, suffix);
}
}
And Now simple Looping the array to find the Total Ways:
int ans=0;
for(int i=1;i<=n-2;i++){
if(dp[i]==1)
{
ans+= (query(n, suffix) - query(i+1, suffix));
// Checking For the Sum/3 in array where index>i+1
}
}
I Getting the wrong answer for the above approachI don't Know where I have made mistake Please Help to Correct my mistake.
Update and Query Function:
public static void update(int i , int value , int[] arr){
while(i<arr.length){
arr[i]+=value;
i+=i&-i;
}
}
public static int query(int i ,int[] arr){
int ans=0;
while(i>0){
ans+=arr[i];
i-=i&-i;
}
return ans;
}
As far as your approach is concerned its correct. But there are some points because of which it might give WA
Its very likely that sum overflows int as each element can magnitude of 10^9, so use long long .
Make sure that suffix and dp array are initialized to 0.
Having said that using a BIT tree here is an overkill , because it can be done in O(n) compared to your O(nlogn) solution ( but does not matter if incase you are submitting on a online judge ).
For the O(n) approach just take your suffix[] array.And as you have done mark suffix[i]=1 if sum from i to n is sum/3, traversing the array backwards this can be done in O(n).
Then just traverse again from backwards doing suffix[i]+=suffix[i-1]( apart from base case i=n).So now suffix[i] stores number of indexs i<=j<=n such that sum from index j to n is sum/3, which is what you are trying to achieve using BIT.
So what I suggest either write a bruteforce or this simple O(n) and check your code against it,
because as far as your approach is concerned it is correct, and debugging is something not suited for
stackoverflow.
First, we calculate an array dp, with dp[i] = sum from 0 to i, this can be done in O(n)
long[]dp = new long[n];
for(int i = 0; i < n; i++)
dp[i] = a[i];
if(i > 0)
dp[i] += dp[i - 1];
Second, let say the total sum of array is x, so we need to find at which position, we have dp[i] == x/3;
For each i position which have dp[i] == 2*x/3, we need to add to final result, the number of index j < i, which dp[j] == x/3.
int count = 0;
int result = 0;
for(int i = 0; i < n - 1; i++){
if(dp[i] == x/3)
count++;
else if(dp[i] == x*2/3)
result += count;
}
The answer is in result.
What wrong with your approach is,
if(dp[i]==1)
{
ans+= (query(n, suffix) - query(i+1, suffix));
// Checking For the Sum/3 in array where index>i+1
}
This is wrong, it should be
(query(n, suffix) - query(i, suffix));
Because, we only need to remove those from 1 to i, not 1 to i + 1.
Not only that, this part:
for(int i=1;i<=n-2;i++){
//....
}
Should be i <= n - 1;
Similarly, this part, for(int i=n ;i>=3;i--), should be i >= 1
And first part:
for(int i=0;i<n;i++){
a[i]= in.nextLong();
sum+=a[i];
}
Should be
for(int i=1;i<=n;i++){
a[i]= in.nextLong();
sum+=a[i];
}
A lot of small errors in your code, which you need to put in a lot of effort to debugging first, jumping to ask here is not a good idea.
In the question asked we need to find three contiguous parts in an array whose sum is the same.
I will mention the steps along with the code snippet that will solve the problem for you.
Get the sum of the array by doing a linear scan O(n) and compute sum/3.
Start scanning the given array from the end. At each index we need to store the number of ways we can get a sum equal to (sum/3) i.e. if end[i] is 3, then there are 3 subsets in the array starting from index i till n(array range) where sum is sum/3.
Third and final step is to start scanning from the start and find the index where sum is sum/3. On finding the index add to the solution variable(initiated to zero), end[i+2].
The thing here we are doing is, start traversing the array from start till len(array)-3. On finding the sum, sum/3, on let say index i, we have the first half that we require.
Now, dont care about the second half and add to the solution variable(initiated to zero) a value equal to end[i+2]. end[i+2] tells us the total number of ways starting from i+2 till the end, to get a sum equal to sum/3 for the third part.
Here, what we have done is taken care of the first and the third part, doing which we have also taken care of the second part which will be by default equal to sum/3. Our solution variable will be the final answer to the problem.
Given below are the code snippets for better understanding of the above mentioned algorithm::-
Here we are doing the backward scanning to store the number of ways to get sum/3 from the end for each index.
long long int *end = (long long int *)calloc(numbers, sizeof(long long int);
long long int temp = array[numbers-1];
if(temp==sum/3){
end[numbers-1] = 1;
}
for(i=numbers-2;i>=0;i--){
end[i] = end[i+1];
temp += array[i];
if(temp==sum/3){
end[i]++;
}
}
Once we have the end array we do the forward loop and get our final solution
long long int solution = 0;
temp = 0;
for(i=0;i<numbers-2;i++){
temp+= array[i];
if(temp==sum/3){
solution+=end[i+2];
}
}
solution stores the final answer i.e. the number of ways to split the array into three contiguous parts having equal sum.