1757698765
2025-09-12 14:44:00
2025年9月10日
ジョブに適切なツールを使用します。
大学を卒業した私の最初のインタビューで、私はChange Counterの問題を尋ねられました:
一連のコインの宗派が与えられた場合、特定の数の変更を加えるために必要なコインの最小数を見つけます。 IEの米国貨幣と37セントの場合、最小数は4(四半期、ダイム、2ペニー)です。
私は単純な貪欲なアルゴリズムを実装し、すぐに質問のtrapに陥りました。貪欲なアルゴリズムは「行儀の良い」宗派にのみ機能します。コインの値があった場合 [10, 9, 1]、37セントを稼ぐと、貪欲なアルゴリズムで10コインが10枚摂取しますが、最適なコインは4コインだけです(10+9+9+9)。 「スマート」の答えは、動的なプログラミングアルゴリズムを使用することですが、それは方法がわかりませんでした。だから私はインタビューに失敗しました。
ただし、独自のアルゴリズムを書いている場合にのみ、動的プログラミングが必要です。あなたがそれをのような制約ソルバーに投げるのは本当に簡単です Minizinc そしてそれを一日と呼んでください。
int: total;
array[int] of int: values = [10, 9, 1];
array[index_set(values)] of var 0..: coins;
constraint sum (c in index_set(coins)) (coins[c] * values[c]) == total;
solve minimize sum(coins);
これをオンラインで試すことができます ここ。それはあなたに投入するプロンプトを与えます total そして、あなたに連続してベッターのソリューションを与えます:
coins = [0, 0, 37];
----------
coins = [0, 1, 28];
----------
coins = [0, 2, 19];
----------
coins = [0, 3, 10];
----------
coins = [0, 4, 1];
----------
coins = [1, 3, 0];
----------
多くの同様のインタビューの質問は、この種の数学的最適化の問題であり、制約に対応する関数の最大または最小を見つける必要があります。プログラミング言語は低レベルであるため、プログラミング言語では困難です。また、制約ソルバーが解決するように設計された問題でもあります。ハードリートコードの問題は、簡単な制約の問題です。 ここでは、Minizincを使用していますが、Z3やOr-Tools、またはお気に入りの一般化ソルバーが何でも簡単に使用できます。
その他の例
これは別のインタビューの質問でした(ありがたいことに合格しました):
1日を通じて株価のリストを考えると、1つの株式を購入して後で1つの株式を販売することで得られる最大の利益を見つけます。
o(n^2)時間で簡単に行うことができます。賢い場合は、o(n)で行うことができます。または、あなたはまったく賢くなく、制約問題としてそれを書くこともできます。
array[int] of int: prices = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8];
var int: buy;
var int: sell;
var int: profit = prices[sell] - prices[buy];
constraint sell > buy;
constraint profit > 0;
solve maximize profit;
リマインダー、オンラインで試してみることへのリンク ここ。その仕事で働いている間、私たちがテストした1つのインタビューの質問は次のとおりです。
リストを指定して、そのリスト内の3つの数値を追加または差し引いて0を与えることができるかどうかを判断しますか?
これは満足の問題であり、制約の問題ではありません。「ベストアンサー」は必要ありません。私たちは最終的に、私たちがターゲットにしていたエンジニアにとってあまりにも注意が必要であることに反対しました。しかし、ソルバーではトリッキーではありません。
include "globals.mzn";
array[int] of int: numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8];
array[index_set(numbers)] of var {0, -1, 1}: choices;
constraint sum(n in index_set(numbers)) (numbers[n] * choices[n]) = 0;
constraint count(choices, -1) + count(choices, 1) = 3;
solve satisfy;
さて、最後の1つ、昨年見た問題 Chipy Algosig。基本的に彼らはいくつかのリートコードの問題を選択し、私たち全員がそれらを行います。私は解決できませんでした これです:
各バーの幅が1のヒストグラムのバーの高さを表す整数高さの配列を考えると、ヒストグラム内の最大の長方形の面積を返します。
「適切な」解決策は、多くの簿記状態を追跡することを伴う難しいものです。これは、制約として表現することで完全にバイパスできます。
array[int] of int: numbers = [2,1,5,6,2,3];
var 1..length(numbers): x;
var 1..length(numbers): dx;
var 1..: y;
constraint x + dx (x+dx))*(y) = (area)"]
する方法さえあります ソリューションを自動的に視覚化します (使用 vis_geost_2d)、しかし、私はニュースレターに間に合うようにそれを理解するつもりはありませんでした。
これはもっといいですか?
今、私が実際にこれらの質問をインタビューに持ってきた場合、インタビュー対象者は「ランタイムの複雑さは何ですか?」と尋ねることで私の一日を台無しにする可能性があります。制約ソルバーのランタイムは予測不可能であり、理想的なオーダーメイドのアルゴリズムよりもほとんど常に常に表現力があるため、私が 能力/扱いやすさのトレードオフ。しかし、それでも、彼らはよりはるかに優れています 悪い オーダーメイドのアルゴリズムであり、私はソルバーを一貫して打ち負かすために手書きのアルゴリズムで十分に経験していません。
ただし、ソルバーの本当の利点は、新しい制約をどの程度うまく処理するかです。上記の在庫ピッキングの問題を取ります。考えてみると、数分でO(n²)アルゴリズムとO(n)アルゴリズムを書くことができます。次に、問題を変更します
売買することにより、利益を最大化します
max_sales在庫、しかし、あなたは特定の時間に1つの株式のみを売買することができ、あなたはしか保持できませんmax_hold一度に在庫?
これは、非効率的なアルゴリズムでさえ書くのが難しい問題です!制約問題は少しだけ複雑ですが、
include "globals.mzn";
int: max_sales = 3;
int: max_hold = 2;
array[int] of int: prices = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8];
array [1..max_sales] of var int: buy;
array [1..max_sales] of var int: sell;
array [index_set(prices)] of var 0..max_hold: stocks_held;
var int: profit = sum(s in 1..max_sales) (prices[sell[s]] - prices[buy[s]]);
constraint forall (s in 1..max_sales) (sell[s] > buy[s]);
constraint profit > 0;
constraint forall(i in index_set(prices)) (stocks_held[i] = (count(s in 1..max_sales) (buy[s]
オンラインでのほとんどの制約解決例は、パズルです 数独 または “+ more = moneyを送信します「。リートコードの問題を解決することは、より興味深いデモンストレーションになるでしょう。そして、対称性の破壊など、最適化を教えるためのより興味深い機会が得られます。
あなたがこれをウェブ上で読んでいるなら、あなたは購読することができます ここ。更新は週に1回です。私の主なウェブサイトはそうです ここ。
私の新しい本、 プログラマーのロジック、今は早期にアクセスしています!それを得る ここ。
#多くのハードリートコードの問題は簡単な制約の問題です