【Hash, double pointer】| AcWing 1532. Find coins

Title description

Eva likes to collect coins from the entire universe.

One day, she went to a universe shopping mall to shop, and she could use various coins to pay at the checkout.

However, there is a special payment requirement: for each bill, she can only use exactly two coins to accurately pay the consumption amount.

Given the denominations of all the coins she has, please help her determine whether she can find two coins to pay for the given amount.

Input format The
first line contains two integers N and M, which respectively represent the number of coins and the amount to be paid.

The second line contains N integers, representing the denomination of each coin.

Output format
Output one line, containing two integers V1, V2, representing the denominations of the two selected coins, such that V1≤V2 and V1+V2=M.

If the answer is not unique, the solution with the smallest V1 is output.

If there is no solution, output No Solution.

Data range
1≤N≤10 5 ,
1≤M≤1000

Input example 1:

8 15
1 2 8 7 2 4 11 15

Output sample 1:

4 11

Input example 2:

7 14
1 8 7 2 4 11 15

Output sample 2:

No Solution

Hash

This question is flawed. It does not tell us the size range of the coin, only the number of coins input is 1e5.

  1. If the range of the coin is much larger than 1e5, then hashing is a better choice;
  2. If the range of the coin is less than 1e5, but the number of coins we input is 1e5, so there must be duplicate coins. You don't need to hash, but just open a 1e5 array to record the number. The subscript represents the coin and the value represents The number of coins.

First of all, you need to be sure that the size of the coin must be a non-negative number, that is, greater than or equal to 1.

Idea :
Process the data when inputting, every time you input a piece of data x, if the number x is greater than or equal to m, it must not match, you can find the next input data, otherwise, you can find the data that has been input before. A y, y=m-xso that it can be made into m. If possible, determine whether v1 in the saved result (v1, v2) is less than the smaller of (x, y). If it is smaller, it is more than Knowing (v1, v2) is closer to the choice of the answer.

Since only two coins are selected, the coins can exist, and there is no need to store duplicate elements.

Special case : When m is an even number, there may be a situation where x=y=m/2, but no special judgment is needed, because when the input is x=m/2, if it is the first input, it will definitely not be possible. , And then insert it; when you input x=m/2 for the second time, you find it when you first judge whether y=m/2 was input before, and then you can make it into m, and then judge whether the current x has been recorded before If there is no record before inserting, this is to limit the existence of repeated elements, so there is still only one m/2, but it does not affect the result.
Generally, both x and y are inserted. x+y=m

But pay attention to comparing whether y has been recorded before and the order of inserting x , you must first compare, and then insert .
Because, if you insert it first,
imagine: when x=m/2, insert x first, and then match whether y has been inserted. At this time, y==x, the match is the newly inserted x, although in fact only An x, but because of the order problem, the match succeeded.

Therefore, it is necessary to match the number y that originally existed in the hash table, and then determine whether x needs to be inserted, and then insert x.

1. Handwritten Hash

#include <iostream>
#define read(x) scanf("%d",&x)

using namespace std;

const int N=3e5+1,M=1010; "N要是素数"
int hs[N];"初始化为0,当遇到0的时候说明哈希表这个位置为空,因为硬币的价值都是大于0的"
int null=0;  "所以哈希表中的0表示null"

int find(int x)
{
    
    
    int k=x%N;
    while (hs[k] && hs[k]!=x) {
    
     "如果遇到的数hs[k]不是0并且不是不是要找的x就不停,继续解决冲突"
        k++;                    "直到遇到0,说明表中不存在x,或者遇到x,说明找到了x"
        if (k==N) k=0;
    }
    return k;  "要么h[k]为空,表示x不存在,k是插入的位置;要么h[k]=x,k是匹配的位置"
}     其实,在这个题里,这个k就是x。

int main()
{
    
    
    int n,m;
    read(n),read(m);
    int v1=M,v2; //(v1,v2)v1先初始化一个可比较且不可能的数
    int x,y;
    while (n--) {
    
    
        read(x);
        if (x>=m) continue; //必然不成立
        y=m-x;  //此时y必然大于0
        int kx=find(x),ky=find(y); //找到x和y在哈希表中存储的下标,或者是否存在于哈希表中
        if (hs[ky]) {
    
     //如果y存在的话,因为输入的是x,所以x必然存在
            if (v1>min(x,y)) v1=min(x,y),v2=max(x,y);
        }
        //接下来判断x是否需要插入,当hs[kx]==null时,说明不存在x,需要插入
        if (!hs[kx]) hs[kx]=x;
    }   "且这个插入必须放在判断if(hs[ky])后面,避免当出现x+x=m的情况时出错。否则当第一次插入x(x=m/2)时就会匹配到,会出错。"
    v1==M?puts("No Solution"):printf("%d %d",v1,v2);

    return 0;
}

2. Simplified writing of (1)

The problem data is limited to 1e5 coins. Choose two of them to make up M. The maximum value of M is 1000.
We don't know the denomination of the input coin. Assuming the denomination is from 1 to 1e5 , set up a bubble array, open to 1e5, the subscript corresponds to the denomination, and the corresponding value indicates how many denominations there are.

#include <iostream>
#define read(x) scanf("%d",&x)

using namespace std;

const int N=1e5+10,M=1010;
int bubble[N];     "记录从1到N的面值的硬币的个数"

int main()
{
    
    
    int n,m;
    read(n),read(m);
    int v1=M,v2,x,y;
    while (n--) {
    
    
        read(x);
        y=m-x;
        if(y>0 && bubble[y]) //避免数组越界,y为负数时,即相当于x>=m时不处理
            if (v1>min(x,y)) v1=min(x,y),v2=max(x,y);
        bubble[x]++;    
    }
     v1==M?puts("No Solution"):printf("%d %d",v1,v2);
    
    return 0;
}

3. Unordered_set implementation

#include <iostream>
#include <unordered_set>
            
using namespace std;

#define read(x) scanf("%d",&x)
const int M=1010;

int main()
{
    
    
    int n,m;
    read(n),read(m);
    int v1=M,v2,x,y;
    unordered_set<int> hash;   //set中不允许有重复元素
    while (n--) {
    
     //边读入边处理
        read(x);
        y=m-x;
        if (hash.count(y)) {
    
    //x已经必然存在
            if (v1>min(x,y)) v1=min(x,y),v2=max(x,y);
        }
        hash.insert(x);  //重复则不插入
    }
    v1==M?puts("No Solution"):printf("%d %d",v1,v2);
    
    return 0;
}

Double pointer

No longer input and process at the same time, after input, then unified processing.

#include <iostream>
#include <algorithm>
#define read(x) scanf("%d",&x)

using namespace std;

const int N=1e5+10;

int main()
{
    
    
    int n,m;
    read(n),read(m);
    int coin[N];
    for (int i=0;i<n;i++) read(coin[i]);
    sort(coin,coin+n); //默认升序
    int i,j;
    for (i=0,j=n-1; i<j ; ) {
    
      //左边往右走,右边往左走,相碰就可以停,相碰说明只剩下选一个硬币的方案,即没答案
        if (coin[i]+coin[j]>m) j--;   "只能用if"
        else if (coin[i]+coin[j]<m) i++;
        else break; //碰到的第一个匹配到的就可以停止,coin[i]此时最小
    }
    i==j?puts("No Solution"):printf("%d %d",coin[i],coin[j]);  "必然不会出现i>j的情况,只可能i==j退出"
    
    return 0;
}

Compare the difference between the two processing

	int i,j;
    for (i=0,j=n-1; i<j ; i++) {
    
      //左边往右走,右边往左走,相碰就可以停,相碰说明只剩下选一个硬币的方案,即没答案
        while (i<j && coin[i]+coin[j]>m) j--;
        if (i<j && coin[i]+coin[j]==m) break;
    }
    i>=j?puts("No Solution"):printf("%d %d",coin[i],coin[j]);   "可能出现i>j的情况"

Guess you like

Origin blog.csdn.net/HangHug_L/article/details/114143449