---
# System prepended metadata

title: Algorithm homework II

---

---
title: Algorithm homework II
---
# Problem 1
- Bubble sort:
    基於 bubble sort 會前項比後項, 因此會直接比較兩個相等值的元素
- Insertion sort:
    Insertion sort 會將比較的值與上一項的值作比較, 若大於比較值上一項的值會寫入到當前比較項的後項, 因此遇到相同值則可以直接 Insert 至相同值的後面
- Quick sort:
## bubble sort
    穩定，基於 bubble sort 會前項比後項, 因此會直接比較兩個相等值的元素，這時候不會交換，如果兩個相等的元素沒有相鄰，也能通過前面的兩兩交換把兩個相鄰起來，所以氣泡排序是一種穩定的排序演算法。
    in place，因為是兩個元素比較，不會用到額外的空間。
## insertion sort
    穩定，將資料分成已排序、未排序兩部份，比較是從已排序序列的末尾開始，也就是想要插入的元素和已經已排序的最大者開始比起，如果比它大則直接插入在其後面，否則一直往前找直到找到它該插入的位置。如果碰見一個和插入元素相等的，那麼插入元素把想插入的元素放在相等元素的後面。所以，相等元素的前後順序沒有改變，所以插入排序是穩定的。
    in place，將資料分成已排序、未排序兩部份，不會用到額外的空間
## quick sort
    不穩定，假設第一個數為基準值，從將比基準值(Pivot)小的數值移到左邊，比基準值大的數值移到右邊, 如果序列為 7 4 5 4 8 9 ，將7和4交換便會將穩定性打亂。
    not in place，因為遞迴需要額外的堆疊空間
## merge sort
    穩定，merge sort會先不斷拆成1個或2個，2個元素如果大小相等也沒有人故意交換，之後合併過程中我們可以保證如果兩個當前元素相等時，我們把處在前面的序列的元素儲存在結果序列的前面，這樣就保證了穩定性。所以，歸併排序也是穩定的排序演算法。
    not in place，需要暫時性的暫列存放每回合Merge後的結果
## heap-sort.
    不穩定, 如果a序列為 7 4 5 4 8 9 4
    第一步將a[2],a[5],a[6]比大小，變為 7 4 9 4 8 5 4
    第二步將a[1],a[3],a[4]比大小，變為 7 8 9 4 4 5 4
    這時相同的元素之間的穩定性就被破壞了。所以，堆排序不是穩定的排序演算法。
    in place，不會用到額外的空間
 


# Problem 2 (solved)
只能算到92681,超過就會卡
```C++
#include <iostream>

using namespace std;

int main(){
  int n, l = 1, r, m;
  cin >> n;
  m = n/2;
  r = n/2;
  while(!(m*m < n && (m + 1)*(m + 1) > n)){
    if(m*m == n){
      cout << m << ' ' << m*m << endl;
      return 0;
    }
    else if(m*m > n)
      r = m;
    else
      l = m;
    m = (l + r)/2;
  }
  cout << m << ' ' << m*m << endl;
}
```
# Problem 3
如何將Merge Sort在額外空間的占用優化至僅使用n/2
(以下方式使用遞迴)
```
第一步:先將原本n個元素組成的數列切割成左右對半，先取左半邊
第二步:繼續切割至數列僅剩一個元素
第三步:開始合併直到取的半邊完全排序好 (在此步驟裡合併好的數列暫存在額外空間中，假設為temp，而它的尺寸為n/2)
第四步:將temp中排序好的數列直接覆蓋原本數列的左半邊
第五步:接著取右半邊，重複執行第二步與第三步
第六步:用排好的原數列左半邊與temp做最後的排序，再將排序好的temp覆蓋原數列的右半邊
```
# Problem 4 (solved)
Data structure
```=c++
#include <iostream>
#include <unordered_set>
#include <vector>
#include <sstream>

using namespace std;

struct Set{
	unordered_set<int> got;
	vector<int> elem;

	Set(){
	    stringstream ss;
	    string s;
	    int n;
    	    getline(cin, s);
	    ss << s;
    	    while(ss >> n){
        	if(got.find(n) == got.end()){
            	    got.insert(n);
	            elem.push_back(n);
    	        }
    	    }
	}
};

void Union(){
	cin.ignore();
	Set s1;
	Set s2;
	unordered_set<int>::iterator i;
	vector<int>::iterator j;
	for(j = s2.elem.begin();j != s2.elem.end();j++){
		if(s1.got.find(*j) == s1.got.end())
			cout << *j << ' ';
	}
	for(i = s1.got.begin();i != s1.got.end();i++)
		cout << *i << ' ';
	cout << endl;
	return;
}

void Intersection(){
	cin.ignore();
	Set s1;
	Set s2;
	vector<int>::iterator i;
	for(i = s2.elem.begin();i != s2.elem.end();i++){
		if(s1.got.find(*i) != s1.got.end())
			cout << *i << ' ';
	}
	cout << endl;
	return;
}

void elem(){
	int t, n;
	stringstream ss;
	string s;
	cin >> t;
	cin.ignore();
	getline(cin, s);
	ss << s;
	while(ss >> n){
		if(n == t){
			cout << "Yes" << endl;
			return;
		}
	}
	cout << "No" << endl;
	return;
}

int main(){
	int n;
	while(1){
		cout << "1.union\n2.intersection\n3.in\n4.quit\ninput #:";
		cin >> n;
		switch (n){
			case 1:
				Union();
				break;
			case 2:
				Intersection();
				break;
			case 3:
				elem();
				break;
			case 4:
				return 0;
			default:
				cout << "No this option" << endl;
		}
		cout << "--------------------------------------" << endl;
	}	
}
 
```
> 幹麻一直偷我要寫的題目 [name=ZoneTwelve][time=Wed, Mar 18, 2020 10:21AM][color=#0084ff]
>> 你就慢[name=vic0103520]
```=c++
// 這還沒寫完
#include <iostream>
#include <vector>

class SET{
  public:
    std::vector<int> array;
    int find(int el);
    void add(int el);
    void print();
    SET union(SET B);
    SET intersection(SET B);
};
int SET::find(int el){
  int l = 0, r = array.size(), c = -1;
  while(l<r){
    c = l + ( ( r - l ) / 2 );
    if(el>array[c]){
      l = c;
    }else if(el<array[c]){
      r = c;
    }else{
      return c;
    }
    std::cout<<l<<" - "<<c<<" - "<<r<<"\n";
  }
}
void SET::add(int el){
  int i = 0;
  for(i;i<array.size()&&array[i]<el;i++){
    if(array[i]==el)
      return;
  }
  array.insert(array.begin()+i, el);
}
SET SET::union(SET B){
  int i;
  while(i<array.size()||i<B.array.size()){
    std::cout<<(i++)<<" ";
  }
}
void SET::print(){for(int i=0;i<array.size();i++)std::cout<<array[i]<<" ";std::cout<<"\n";}

int main(){
  SET A;
  std::cout<<"Hello\n";
  A.add(3);
  A.add(1);
  A.add(4);
  A.add(2);
  A.print();
  std::cout<<"Program end;\n";
}
```

# Problem 5 (solved)
## 解法1:
演算法概念:
    透過已排序的兩個陣列去做 binary search 來搜尋X中的每項相對最接近的值
    要求: min i, j (|X[i] - Y[j]|) 項
    X[m], Y[n]
    binary search => O(M$\log_{2}{n}$)
```C++
#include <iostream>
#include <vector>

std::vector<int> X; // 3, 5, 7
std::vector<int> Y; //  4 , 7

int abs(int a){return a>0?a:-a;}
void minimum(std::vector<int> X, std::vector<int> Y){
  int min = 99999;
  int ri, rj;
  for(int x=0;x<X.size();x++){
    int l = 0, r = Y.size();
    int c;
    while(l<r){
      c = l + (r - l) / 2;
      if(X[x]>Y[c]){
        l+=c;
      }else if(X[x]<Y[c]){
        r-=c+1;
      }else{
        break;
      }
    }
    if(min>abs(X[x]-Y[c])){
      min = abs(X[x]-Y[c]);
      ri = x;
      rj = c;
    }
  }
  std::cout<<"result: "<<min<<" - "<<ri<<", "<<rj<<"\n";
}

int main(){
  int xlen = 5, ylen = 5;
  //int x[xlen] = {3, 5, 7};
  //int y[ylen] = { 4 , 7 };
  int x[xlen] = {1, 4, 8, 9, 10};
  int y[ylen] = {2, 3 ,7, 8, 10};
  for(int i=0;i<xlen;i++)
    X.push_back(x[i]);
  for(int i=0;i<ylen;i++)
    Y.push_back(y[i]);
  //for(int i=0;i<Y.size();i++)
  //  std::cout<<Y[i]<<" ";
  minimum(X, Y);
}
```
> 有 bug [name=ZoneTwelve][time=Wed, Mar 18, 2020 10:32 AM][color=#0084ff]

## 解法2:
>修是修好了,但index可能會倒過來:)[name=中央第一網管]
>> 臭87 [name=ZoneTelve][color=#0084ff]

> 我發現Y的尾巴大就不會出問題,所以先比較最後一項再決定怎麼call
> 原本
> 1 2 10 
> 5 6 9 
> 會出問題,j在X比較大的時候會跑出input,Y[j]會變成零,所以簡單的解決辦法就是先比較再call
> [name=中央最強網管]
> 
> Time complexity O(M+N)
```C++
#include <iostream>
#include <vector>

using namespace std;

int abs(int x){return x >= 0 ? x : -x;}

void minimum(vector<int> x, vector<int> y){
	int i, j = 0, min = 999999, a, b;
	for(i = 0;i < x.size();i++){
		for(;j < y.size() && y[j] < x[i];j++){}
		if(y[j] == x[i]){
			cout << i << ' ' << j << ' ' << 0 << endl;
			return;
		}
		else if(y[j] - x[i] < min || j > 0 && x[i] - y[--j] < min){
			min = abs(y[j] - x[i]);
			a = i;
			b = j;
		}
	}
	cout << a << ' ' << b << ' ' << min << endl;
	return;
}

int main(){
	vector<int> X, Y;
	int n;
	while(cin >> n){
		if(n == 0)
			break;
		X.push_back(n);
	}
	while(cin >> n){
		if(n == 0)
			break;
		Y.push_back(n);
	}
	X.back() > Y.back() ? minimum(Y, X) : minimum(X, Y);
}
```
# Problem 6 (solved)
    T(n) = 2T(n/2)+n-1
         = 4T(n/4)+2n-(1+2)
         = 8T(n/8)+3n-(1+2+4)
             .
             .
             .
         = 2^(k-1)*T(2)+(k-1)n-(2^(k-1)-1)
         = cn/2+n(lgn-1)-n/2+1
         = nlgn+(c/2-3/2)n+1
         
# Problem 7
## Solution:
```=c++
#include <bits/stdc++.h>
#include <sstream>
std::vector<int> keys;
class SET{
public:
  int length;
  std::vector<int> keys;
  std::map<int, int> set;
  
  SET(){length = 0;}
  void pushme(int);
};
void SET::pushme(int el){
  keys.push_back(el);
  set[el] = el;
  length++;
}

void solution(SET mySet, int x, std::string com = "", int n = 0, int result = 0){
  std::stringstream ss;
  std::string tmp;
  for(int i=n+1;i<mySet.length+1;i++){
    ss<<mySet.keys[n];
    ss>>tmp;
    if(i<mySet.length)
      solution(mySet, x, com+tmp+" ", i, result+mySet.keys[n]);
  }
  if(result==x)
    std::cout<<result<<"\t"<<com<<"\n";
}

int main(){
  int x, tmp;
  SET mySet;

  std::cin>>x;
  while(std::cin>>tmp)
    mySet.pushme(tmp);
  
  std::cout<<"---Program run---\n";
  solution(mySet, x);
  std::cout<<"---Program end---\n";
}
```

## 描述拉幹:
題目：判斷可否從n個數字中找出k個數和為M
作法：從n個數中取一數稱t,再從剩下n-1個中找是否有k-1個數和為M-t,持續此動作直到k＝1,若M'=k則true else false
分析：此作法等同找出任意大小為k,和為M之組合,每個動作都找出一個樣本,則動作總數為樣本空間之大小C(n, k)=>時間複雜度為min(O(n^k), O(n^(n-k))).
