How to filter multiple many to many relationship based on multiple tags?
I had just asked that on a different forum.  The best solution for a 3rd Normal Form schema design was to select all that is needed in the linking table and compare the Cardinality (count) of the matching results.

The other forum was for Oracle.  The answer you seek is the PostgreSQL version of this post: https://community.oracle.com/message/15613817#15613817

-- copy paste from original post
-- Oracle version
select *     
from my_recipes rp    
where rp.recipe_id  in  
(    
    select tg.recipe_id     
    from my_recipe_tags tg    
    where tg.tag_id in    (
                            -- expands string '1:2:3' into a table w/ 3 row    
                            select to_number(regexp_substr(:p_search_tags,'[^:]+', 1, level) )    
                            from  dual    
                            connect by regexp_substr(:p_search_tags, '[^:]+', 1, level) is not null    
                        )   
    group by tg.recipe_id                         
                      -- counts cardinality of Tags in search
    having count(*) = regexp_count(:p_search_tags, '[^:]+')                               
) ;


Untested (needs to be fixed)

select *
from PROBLEMS p
where p.id in (
    select pt.problem_id
    from PROBLEM_TAGS pt
        join TAGS t on pt.tag_id = t.tag_id
    where t.name in ('math','binary search', 'brute force') -- should be from a CTE
    group by pt.problem_id
    having count(*) = 3 -- count(*) from CTE
)


For the 2nd version, add AND p.id NOT IN clause.

For the 3rd version add a filter that ensures pt.problem_id has the exact cardinality of the queried tags.

and p.id in (
    select pt.problem_id
    from PROBLEM_TAGS pt
    group by pt.problem_id
    having count(*) = 2 -- you have two tags for 3rd one
                        -- you should pull Cardinality from CTE also
)