Is this algorithm using DP? - java

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;
}

Related

Is there a better way to write this code? (Finding lowest number AND greatest number in array) [Java]

So I have this piece of code which basically is trying to find the largest number in an array and the smallest number (here it's ticket price). But I find myself writing two for loops, I was wondering if there was a more efficient way to write this?
/** Setting cheapestCost to the index of the cheapest transport obj*/
for(int i = 0; i < 15; i++) {
if(allTransports[cheapestCost].getTicketPrice() > allTransports[i].getTicketPrice()) {
cheapestCost = i;
}
}
/** Setting greatestCost to the index of the most expensive transport obj*/
for(int i = 0; i < 15; i++) {
if(allTransports[greatestCost].getTicketPrice() < allTransports[i].getTicketPrice()) {
greatestCost = i;
}
}
Thanks!
It seems to me you can just combine those two loops:
for(int i = 0; i < 15; i++) {
int price = allTransports[i].getTicketPrice();
if(allTransports[cheapestCost].getTicketPrice() > price) {
cheapestCost = i;
}
if(allTransports[greatestCost].getTicketPrice() < price) {
greatestCost = i;
}
}
Why dont use array sort ?
Int[] Tickets = new int[TicketsPrice.length]
For(int i =0;i < Tickets.length ; i++){
Tickets[i] = TicketsPrice.getPrice();
}
Int[] Arr = Arrays.sort(Tickets)
Arr[0] \\ => smallest number
Arr[Arr.length -1] \\=> largest number
There is a trick that reduces the number of comparisons you have to do. Divide the array into pairs, and make a comparison in each pair. The higher number in the pair is a candidate for highest element, so make one compare there. The lower number in the pair is a candidate for lowest element, so make one compare there. This costs you three compares per two numbers, whereas the straightforward way costs you two compares per number or four compares per two numbers.
Whether it’s any better is a matter of taste. You may use a stream operation:
/** Setting cheapestCost to the index of the cheapest transport obj*/
int cheapestCost = IntStream.range(0, 15)
.boxed()
.min(Comparator.comparing(i -> allTransports[i].getTicketPrice()))
.orElseThrow();
Similarly for the most expensive transport ticket, just use max() instead of min().
One simple way, you should sort the array by ascending of ticket price then get the first and last element.
But do not change the original order of the array, just store the sorted array in a new variable.
Transport[] allTransports = {new Transport(), new Transport()};
List<Integer> naturalSortedPrices =
Arrays.stream(allTransports).map(Transport::getTicketPrice).sorted()
.collect(Collectors.toList());
int cheapestCost = naturalSortedPrices.get(0);
int greatestCost = naturalSortedPrices.get(naturalSortedPrices.size() - 1);

Two sum - Doesn't work

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Consider input [3,2,4] and target is 6. I added (3,0) and (2,1) to the map and when I come to 4 and calculate value as 6 - 4 as 2 and when I check if 2 is a key present in map or not, it does not go in if loop.
I should get output as [1,2] which are the indices for 2 and 4 respectively
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] arr = new int[2];
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i = 0;i < len; i++)
{
int value = nums[i] - target;
if(map.containsKey(value))
{
System.out.println("Hello");
arr[0] = value;
arr[1] = map.get(value);
return arr;
}
else
{
map.put(nums[i],i);
}
}
return null;
}
I don't get where the problem is, please help me out
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice. Consider input [3,2,4] and target is 6. I added (3,0) and (2,1) to the map and when I come to 4 and calculate value as 6 - 4 as 2 and when I check if 2 is a key present in map or not, it does not go in if loop.
Okay, let's take a step back for a second.
You have a list of values, [3,2,4]. You need to know which two will add up 6, well, by looking at it we know that the answer should be [1,2] (values 2 and 4)
The question now is, how do you do that programmatically
The solution is (to be honest), very simple, you need two loops, this allows you to compare each element in the list with every other element in the list
for (int outter = 0; outter < values.length; outter++) {
int outterValue = values[outter];
for (int inner = 0; inner < values.length; inner++) {
if (inner != outter) { // Don't want to compare the same index
int innerValue = values[inner];
if (innerValue + outterValue == targetValue) {
// The outter and inner indices now form the answer
}
}
}
}
While not highly efficient (yes, it would be easy to optimise the inner loop, but given the OP's current attempt, I forewent it), this is VERY simple example of how you might achieve what is actually a very common problem
int value = nums[i] - target;
Your subtraction is backwards, as nums[i] is probably smaller than target. So value is getting set to a negative number. The following would be better:
int value = target - nums[i];
(Fixing this won't fix your whole program, but it explains why you're getting the behavior that you are.)
This code for twoSum might help you. For the inputs of integer array, it will return the indices of the array if the sum of the values = target.
public static int[] twoSum(int[] nums, int target) {
int[] indices = new int[2];
outerloop:
for(int i = 0; i < nums.length; i++){
for(int j = 0; j < nums.length; j++){
if((nums[i]+nums[j]) == target){
indices[0] = i;
indices[1] = j;
break outerloop;
}
}
}
return indices;
}
You can call the function using
int[] num = {1,2,3};
int[] out = twoSum(num,4);
System.out.println(out[0]);
System.out.println(out[1]);
Output:
0
2
You should update the way you compute for the value as follows:
int value = target - nums[i];
You can also check this video if you want to better visualize it. It includes Brute force and Linear approach:

No. of ways to divide an array

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.

Given an array, find all subsets which sum to value k

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.

Modifying the greatest elements of an array without changing their position?

I'm trying to figure out how to modify the n greatest elements of an array without modifying their position. For example, suppose I have an array of ints {5, 2, 3, 4, 8, 9, 1, 3};
I want to add 1 to the two greatest elements, making the array {5, 2, 3, 4, 9, 10, 1, 3}.
All of the methods I can think of to go about doing this end up feeling clunky and unintuitive when I try to implement them, signaling to me that I'm not thinking about it correctly. For example, I could use a TreeMap with the values of the array as keys and their indices as values to find the greatest values, modify them, and then throw them back into the array, but then I would have have to implement my own Comparator to sort the TreeMap in reverse order(unless there's an easier way I'm not aware of?). I was also considering copying the contents of the array into a list, iterating through n times, each time finding the greatest element and its index, putting the modified greatest element back into the array at that index, removing the element from the list, and repeat, but that feels sloppy and inefficient to me.
Any suggestions as to how to approach this type of problem?
The simplest thing would be to scan your array, and store the indices of the n highest values. Increment the values of those elements.
This is going to be O(n) performance, and I don't think any fancier methods can beat that.
edit to add: you can sort the array in place in O(n) at best, in which case you can get the n highest values very quickly, but the requirement is to not change position of the elements, so you'd have to start with a copy of the array if you wanted to do that (or preserve ordering information so you could put everything back afterward).
You might be over engineering the solution to this problem: scan the array, from beginning to end, and mark the two largest elements. Return to the two greatest elements and add 1 to it. The solution shouldn't be longer than 10 lines.
Loop over the array and keep track of the indices and values of the two largest items
a. Initialize the tracker with -1 for an index and MIN_INT for a value or the first two values of the array
b. At each step of the loop compare the current value against the two tracker values and update if necessary
Increment the two items
Any algorithm you choose should be O(n) for this. Sorting and n passes are way overkill.
Find the nth largest element (call it K) using techniques here and here (can be done in linear time), then go through the array modifying all elements >= K.
i would do something like this
int[] indices = new int[2];
int[] maximas = new int[] { 0, 0 };
int[] data = new int[] { 3, 4, 5, 1, 9 };
for (int i = 0; i < 5; ++i)
{
if (data[i] > maximas[1])
{
maximas[0] = maximas[1];
maximas[1] = data[i];
indices[0] = indices[1];
indices[1] = i;
}
else if (data[i] > maximas[0])
{
maximas[0] = data[i];
indices[0] = i;
}
}
didn't test it, but I think it should work :)
I have tought a bit about this but I cannot achieve more than worstcase:
O( n + (m-n) * n ) : (m > n)
best case:
O(m) : (m <= n)
where m = number of values, n = number of greatest value to search
This is the implementation in C#, but you can easily adapt to java:
int n = 3;
List<int> values = new List<int> {1,1,1,8,7,6,5};
List<int> greatestIndexes = new List<int>();
for (int i = 0; i < values.Count; i++) {
if (greatestIndexes.Count < n)
{
greatestIndexes.Add(i);
}
else {
int minIndex = -1, minValue = int.MaxValue;
for (int j = 0; j < n; j++)
{
if (values[greatestIndexes[j]] < values[i]) {
if (minValue > values[greatestIndexes[j]])
{
minValue = values[greatestIndexes[j]];
minIndex = j;
}
}
}
if (minIndex != -1)
{
greatestIndexes.RemoveAt(minIndex);
greatestIndexes.Add(i);
}
}
}
foreach (var i in greatestIndexes) {
Console.WriteLine(values[i]);
}
Output:
8
7
6

Categories

Resources