Understanding Bubble Sort (Algorithm) - c++

I'm trying to understand the simplest of all swapping algorithms, the bubblesort. Yet I seem to be confused on the steps of actually swapping values, for instance consider the code :
void bubbleSort(int arr[], int n) {
bool swapped = true;
int j = 0;
int tmp;
while (swapped) {
swapped = false;
j++;
for (int i = 0; i < n - j; i++) {
if (arr[i] > arr[i + 1]) {
tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
swapped = true;
}
}
}
}
Let's say I have a list of numbers like this:
7 1 3 4 6 3 5
And I want to swap the first two values, 7 and 1:
By my logic, this is how I'm understanding this code:
set a temp variable equal to 7, so
temp = 7;
set 7 equal to the next value, so
7 = 1; ?
The list at the moment is:
1 1 3 4 6 3 5
Where temp = 7
Now set 1 equal to temp, which is 7?
1 = temp;
So the list is now:
1 7 3 4 6 3 5
Is my understanding correct on this?

First, you do seem to be on the right track.
Some tips to help you progress further on your journey.
Learn the standard template library. There is a function called swap which does exactly what it says on the tin.
Secondly use containers. They are less error prone than C-style arrays.
Finally here is bubble sort explained via the medium of folk dancing.

In this code snippet
if (arr[i] > arr[i + 1]) {
tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
swapped = true;
}
you need to swap two objects arr[i] and arr[i + 1]
If you write directly
arr[i] = arr[i + 1];
then the two objects will have the same value that is the previous value of arr[i] will be lost.
So at first you need to preserve this value somewhere. To do so there is declared an auxiliary intermediate variable tmp
So at first the value of arr[i] is preserved in variable tmp
Let's assume that arr[i] has value 7 and arr[i + 1] has value 1.
tmp = arr[i];
Now tmp and arr[i] has the same value 7.
Then arr[i] is overwritten by the value of arr[i + 1]
arr[i] = arr[i + 1];
Now these two variables have the same value 1 that is the value of arr[i + 1]
We have tmp is equal to 7, arr[i] and arr[i + 1] are equal to 1
However the previous value of arr[i] was preserved in variable tmp
So now this value is assigned to arr[i + 1]
arr[i + 1] = tmp;
And we are getting arr[i + 1] is eqal to 7 and arr[i] is equal tp 1
Thus the values were swapped.

Related

how to update the elements of an array with the sum of previous two and next two elements?

how to update the elements of an array with the sum of previous two and next two elements ? given that for the first element the sum would be the sum of next two elements as there is no previous element and same is the case for last element.
for example given an array {1,2,3} the array will be updated as {5,4,3}
explanation: for 1 there is no previous element so it will be udated as 2+3=5, for 2 there is only 1 previous and only 1 next element so it will be updated as 1+3=4, similarly for 3 it will be 1+2=3.
i tried doing this with if else loops but that seems too confusing and lengthy is there any other way to solve this?
for(int i=0;i<n;i++){
if(i==0){
sum=arr[1]+arr[2];
}
if(i==1){
sum=arr[0]+arr[2]+arr[3];
}
if(i==n-1){
sum=arr[n-2]+arr[n-3];
}
if(i==n-2){
sum=arr[n-1]+arr[n-3]+arr[n-4];
}
}
the above code does not work for n==3 because element at i==1 will be same as n-2 , also this code is so lengthy. how should i solve this question?
You need to create a temporary array to store the initial value of arr to prevent calculating the new value of arr[i] using new values (post-update) of arr[i - 1], arr[i - 2], etc.
std::vector<int> initial_value(arr, arr + n);
for (int i = 0; i < n; ++i) {
int updated_value = 0;
if (i - 2 >= 0) {
updated_value += initial_value[i - 2];
}
if (i - 1 >= 0) {
updated_value += initial_value[i - 1];
}
if (i + 1 < n) {
updated_value += initial_value[i + 1];
}
if (i + 2 < n) {
updated_value += initial_value[i + 2];
}
arr[i] = updated_value;
}
You could use some logic like this if u are looking for minimal code
Psuedo code
for(int i=0;i<sizeof(arr);i++){
int sum = 0;
int startIndex = (i+2) > sizeof(arr) ? sizeof(arr) : (i+2) ;
while(startIndex > (i - 2) && startIndex > 0)
{
if(startIndex == i) continue;
sum = sum + arrCopy[startIndex];
startIndex --;
}
arr[i] = sum;
}

Min sum of distances (absolute differences) between array element and set of k array elements

I need to find the minimum sum of the distances between an element in the array and the set of k-elements of the array, not including that index.
For example:
arr = {5, 7, 4, 9}
k = 2
min_sum(5) = |5-4| + |5-7| = 3
min_sum(7) = |7-9| + |7-5| = 4
min_sum(4) = |4-5| + |4-7| = 4
min_sum(9) = |9-7| + |9-5| = 6
So, a naive solution would be to subtract the i-th element from each element of the array, then sort the array and calculate the sum of the first k elements in the sorted array. But it takes too long... I believe this is a dp-problem or something like that (maybe treaps).
Input:
n - number of array elements
k - number of elements in a set
array
Constraints:
2 <= n <= 350 000
1 <= k < n
1 <= a[i] <= 10^9
time limit: 2 seconds
Input:
4
2
5 7 4 9
Output:
3 4 4 6
What is the most efficient way to solve this problem? How to optimize the search for the minimum sum?
This is my code in C++, and it works about 3 mins for n = 350 000, k = 150 000:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k, tp;
unsigned long long temp;
cin >> n >> k;
vector<unsigned int> org;
vector<unsigned int> a;
vector<unsigned long long> cum(n, 0);
//unordered_map <int, long long> ans;
unordered_map <int, long long> mp;
for (int i = 0; i < n; i++){
cin >> tp;
org.push_back(tp);
a.push_back(tp);
}
/*
srand(time(0));
for (int i = 0; i < n; i++){
org.push_back(rand());
a.push_back(org[i]);
}
*/
sort(a.begin(), a.end());
partial_sum(a.begin(), a.end(), cum.begin());
mp[a[0]] = cum[k] - cum[0] - a[0] * k;
//ans[a[0]] = mp[a[0]];
for (int i = 1; i <= k; i++) {
mp[a[i]] = a[i] * i - cum[i-1] + cum[k] - cum[i] - a[i] * (k-i);
}
for (int i = 1; i < n-k; i++){
for (int j = 0; j <= k; j++){
//if (ans.find(a[i+j]) != ans.end()) {continue;}
temp = ( (a[i+j] * j) - (cum[i+j-1] - cum[i-1]) ) + ( cum[i+k] - cum[i+j] - a[i+j] * (k-j) );
if (mp.find(a[i+j]) == mp.end()) { mp[a[i+j]] = temp; }
else if (mp[a[i+j]] > temp) { mp[a[i+j]] = temp; }
//else { ans[a[i+j]] = mp[a[i+j]]; }
}
}
for (int i = 0; i < n; i++) {
cout << mp[org[i]] << " ";
}
return 0;
}
We can solve this problem efficiently by taking the sliding window approach.
It seems safe to assume that there are no duplicates in the array. If it contains duplicates, then we can simply discard them with the help of HashSet.
The next step is to sort the array to guarantee that the closest k elements will be within the window [i - k; i + k] for each index i.
We will keep three variables for the window: left, right and currentSum. They will be adjusted accordingly at each iteration. Initially, left = 0 and right = k(since the element at index 0 doesn't have elements to its left) and currentSum = result for index 0.
The key consideration is that the variables left and right are unlikely to change 'significantly' during the iteration. To be more precise, at each iteration we should attempt to move the window to the right by comparing the distances nums[i + right + 1] - nums[i] vs nums[i] - nums[i - left]. (You can prove mathematically that there is no point in trying to move the window to the left.) If the former is less than the latter, we increment right and decrement left while updating currentSum at the same time.
In order to recalculate currentSum, I would suggest writing down expressions for two adjacent iterations and looking closer at the difference between them.
For instance, if
result[i] = nums[i + 1] + ... + nums[i + right] - (nums[i - 1] + ... + nums[i - left]) + (left - right) * nums[i], then
result[i] = nums[i + 2] + ... + nums[i + right] - (nums[i] + ... + nums[i - left]) + (left - right + 2) * nums[i + 1].
As we can see, these expressions are quite similar. The time complexity of this solution is O(n * log(n)). (my solution in Java for n ~ 500_000 and k ~ 400_000 works within 300 ms) I hope this together with the consideration above will help you.
Assuming that we have sorted the original array nums and computed the mapping element->its index in the sorted array(for instance, through binary search), we can proceed with finding the distances.
public long[] findMinDistances(int[] nums, int k) {
long[] result = new long[nums.length];
long currentSum = 0;
for (int i = 1; i <= k; i++) {
currentSum += nums[i];
}
result[0] = currentSum - (long) k * nums[0];
int left = 0;
int right = k;
currentSum = result[0];
for (int i = 1; i < nums.length; i++) {
int current = nums[i];
int previous = nums[i - 1];
currentSum -= (long) (left - right) * previous;
currentSum -= previous;
if (right >= 1) {
currentSum -= current;
left++;
right--;
} else {
currentSum += nums[i - 1 - left];
}
currentSum += (long) (left - right) * current;
while (i + right + 1 < nums.length && i - left >= 0 &&
nums[i + right + 1] - current < current - nums[i - left]) {
currentSum += nums[i + right + 1] - current;
currentSum -= current - nums[i - left];
right++;
left--;
}
result[i] = currentSum;
}
return result;
}
For every element e in the original array its minimal sum of distances will be result[mapping.get(e)].
I think this one is better:
Sort the array first then you can know that fact -
For every element i in the array the k minimum distances of it with other elemets will be the distances with the ones that in k places around it in the array.
(of course it's maybe to the right or to the left or from both sides).
So for every element i to calculate min_sum(a[i]) do that:
First, min_sum(a[i]) = 0.
Then, go with two indexes, let's mark them r (to the right of i) and l (to the left of i)
and compare the distance (a[i]-a[r]) with the distance (a[i]-a[l]).
You will add the smallest to min_sum(a[i]) and if it was the right one then
increas index r, and if it was the left one then decrease index l.
Of course if the left got to 0 or the right one got to n you will most take the distaces with elemets from the other side.
Anyway you do that till you sum k elemets and that's it.
This way you didn't sort any thing but the main array.

About Climbing n-th stair problem with 2, 3 or 4 steps

My problem is
You are climbing a stair case. Each time you can either make 2 step, 3 steps or 4 steps. The staircase has n steps. In how many distinct ways can you climb the staircase?
This is my code:
int count(int n)
{
int a[n + 1];
a[0] = 0;
a[1] = 0;
a[2] = 1;
a[3] = 1;
a[4] = 2;
for (int i = 5; i <= n; i++)
a[i] = a[i - 4] + a[i - 3]
+ a[i - 2];
return a[n];
}
Is my code correct for every test? and how to check when N is very high to count?

Coursera DSA Algorithmic toolbox week 4 2nd question- Partitioning Souvenirs

Problem Statement-
You and two of your friends have just returned back home after visiting various countries. Now you would
like to evenly split all the souvenirs that all three of you bought.
Problem Description
Input Format- The first line contains an integer ... The second line contains integers v1, v2, . . . ,vn separated by spaces.
Constraints- 1 . .. . 20, 1 . .... . 30 for all ...
Output Format- Output 1, if it possible to partition 𝑣1, 𝑣2, . . . , 𝑣𝑛 into three subsets with equal sums, and
0 otherwise.
What's Wrong with this solution? I am getting wrong answer when I submit(#12/75) I am solving it using Knapsack without repetition taking SUm/3 as my Weight. I back track my solution to replace them with 0. Test cases run correctly on my PC.
Although I did it using OR logic, taking a boolean array but IDK whats wrong with this one??
Example- 11
17 59 34 57 17 23 67 1 18 2 59
(67 34 17)are replaced with 0s. So that they dont interfare in the next sum of elements (18 1 23 17 59). Coz both of them equal to 118(sum/3) Print 1.
#include <iostream>
#include <vector>
using namespace std;
int partition3(vector<int> &w, int W)
{
int N = w.size();
//using DP to find out the sum/3 that acts as the Weight for a Knapsack problem
vector<vector<int>> arr(N + 1, vector<int>(W + 1));
for (int k = 0; k <= 1; k++)
{
//This loop runs twice coz if 2x I get sum/3 then that ensures that left elements will make up sum/3 too
for (int i = 0; i < N + 1; i++)
{
for (int j = 0; j < W + 1; j++)
{
if (i == 0 || j == 0)
arr[i][j] = 0;
else if (w[i - 1] <= j)
{
arr[i][j] = ((arr[i - 1][j] > (arr[i - 1][j - w[i - 1]] + w[i - 1])) ? arr[i - 1][j] : (arr[i - 1][j - w[i - 1]] + w[i - 1]));
}
else
{
arr[i][j] = arr[i - 1][j];
}
}
}
if (arr[N][W] != W)
return 0;
else
{
//backtrack the elements that make the sum/3 and = them to 0 so that they don't contribute to the next //elements that make sum/3
int res = arr[N][W];
int wt = W;
for (int i = N; i > 0 && res > 0; i--)
{
if (res == arr[i - 1][wt])
continue;
else
{
std::cout << w[i - 1] << " ";
res = res - w[i - 1];
wt = wt - w[i - 1];
w[i - 1] = 0;
}
}
}
}
if (arr[N][W] == W)
{
return 1;
}
else
{
return 0;
}
}
int main()
{
int n;
std::cin >> n;
vector<int> A(n);
int sum = 0;
for (size_t i = 0; i < A.size(); ++i)
{
int k;
std::cin >> k;
A[i] = k;
sum += k;
}
if (sum % 3 == 0)
std::cout << partition3(A, sum / 3) << '\n';
else
std::cout << 0;
}
Sum/3 can be achieved by multiple ways!!!! So backtracking might remove a subset that has an element that should have been a part of some other subset
8 1 6 is 15 as well as 8 2 5 makes 15 so better is u check this
if(partition3(A, sum / 3) == sum / 3 && partition3(A, 2 * (sum / 3)) == 2 * sum / 3 && sum == partition3(A, sum))

Divide array integer 2 even sums

I am finding hard to solve this programming problem. I am required to take an array of integers that can be of size N, anywhere from 2 <= N <= 30. I need to divide the array into two smaller arrays whose sums are equal, and if they are not equal, they need to be as close as possible to the same value. I would guess that using some sort of recursive function would be ideal in this situation, but if not, a dynamically programmed solution would work just as well.
I guess you can review wikipedia article on Partition problem. It provides a pseudocode of pseudopolynomial algorithm in c# which you can rather easily convert into c++:
public static bool BalancePartition(int[] S)
{
int n = S.Length;
int N = S.Sum();
bool[,] P = new bool[N / 2 + 1, n + 1];
for (int i = 0; i < n + 1; i++)
P[0, i] = true;
for (int i = 1; i <= N / 2; i++)
for (int j = 1; j <= n; j++)
if (S[j - 1] <= i)
P[i, j] = P[i, j - 1] || P[i - S[j - 1], j - 1];
else
P[i, j] = P[i, j - 1];
return P[N / 2, n];
}