Ini adalah pertanyaan wawancara dari google. Saya tidak bisa menyelesaikannya sendiri. Adakah yang bisa menjelaskan?
Tulis program untuk mencetak urutan penekanan tombol sedemikian rupa sehingga menghasilkan jumlah maksimum karakter 'A'. Anda diperbolehkan untuk menggunakan hanya 4 tombol: A, Ctrl+ A, Ctrl+ Cdan Ctrl+ V. Hanya diperbolehkan menekan tombol N. Semua Ctrl+ karakter dianggap sebagai satu tombol, jadi Ctrl+ Aadalah satu tombol.
Misalnya, urutan A, Ctrl+ A, Ctrl+ C, Ctrl+ Vmenghasilkan dua A dalam 4 penekanan tombol.
- Ctrl + A adalah Pilih Semua
- Ctrl + C adalah Salin
- Ctrl + V adalah Tempel
Saya melakukan matematika. Untuk setiap N, menggunakan x bilangan A, satu Ctrl+ A, satu Ctrl+ Cdan y Ctrl+ V, kita dapat menghasilkan max ((N-1) / 2) 2 bilangan A. Untuk beberapa N> M, lebih baik untuk digunakan sebagai banyak Ctrl+ A's, Ctrl+ Cdan Ctrl+ Vurutan seperti menggandakan jumlah A.
Urutan Ctrl+ A, Ctrl+ V, Ctrl+ Ctidak akan menimpa pilihan yang ada. Ini akan menambahkan pilihan yang disalin ke yang dipilih.
^A
biasanya "pilih semua",^C
adalah "salin",^V
adalah "tempel". Apakah itu memberi Anda gambaran?Jawaban:
Ada solusi pemrograman dinamis. Kita mulai dengan mengetahui bahwa 0 kunci dapat membuat kita menjadi 0 A. Kemudian kami mengulang
i
hinggan
, melakukan dua hal: menekan A sekali dan menekan pilih semua + salin diikuti denganj
waktu tempel (sebenarnya dij-i-1
bawah; perhatikan triknya di sini: konten masih di clipboard, jadi kami dapat menempelkannya beberapa kali tanpa menyalin setiap kali). Kita hanya perlu mempertimbangkan hingga 4 paste berturut-turut, karena pilih, salin, tempel x 5 sama dengan memilih, menyalin, menempel, memilih, menyalin, menempel dan yang terakhir lebih baik karena meninggalkan kita lebih banyak di clipboard. Setelah kami mencapain
, kami mendapatkan hasil yang diinginkan.Kompleksitasnya mungkin tampak seperti O (N), tetapi karena bilangan tersebut tumbuh pada tingkat eksponensial, sebenarnya ia adalah O (N 2 ) karena kerumitan mengalikan bilangan besar. Di bawah ini adalah implementasi Python. Diperlukan waktu sekitar 0,5 detik untuk menghitung N = 50.000.
Di dalam kode,
j
mewakili jumlah total tombol yang ditekan setelah urutan penekanan tombol baru kami. Kami sudah memilikii
penekanan tombol pada tahap ini, dan 2 penekanan tombol baru menuju ke pilih-semua dan salin. Oleh karena itu kami menekanj-i-2
waktu tempel . Karena menempelkan menambah urutan yang adadp[i]
A
, kita perlu menambahkan1
membuatnyaj-i-1
. Ini menjelaskanj-i-1
di baris ke-2 terakhir.Berikut adalah beberapa hasil (
n
=> jumlah A):Saya setuju dengan @SB bahwa Anda harus selalu menyatakan asumsi Anda: Milik saya adalah Anda tidak perlu menempelkan dua kali untuk menggandakan jumlah karakter. Ini mendapat jawaban untuk 7, jadi kecuali solusi saya salah, asumsi itu pasti benar.
Dalam kasus seseorang keajaiban mengapa saya tidak memeriksa urutan bentuk Ctrl+ A, Ctrl+ C, A, Ctrl+ V: Hasil akhir akan selalu sama dengan A, Ctrl+ A, Ctrl+ C, Ctrl+ Vyang saya lakukan mempertimbangkan.
sumber
n => result
atauresult => n
? Bagaimanapun, saya pikir itu salah. Kita bisa mengetik 9 As dengan 7 penekanan tombol. Kalau sudahn => result
pasti salah. Jumlah As yang dapat Anda ketik tidak boleh lebih rendah darin
.n => result
. Anda mengatakan "Kita bisa mengetik 9 As dengan 7 penekanan tombol", itulah yang saya dapatkan. Baca "trik" yang baru saja saya edit.n
adalah penekanan tombol yang boleh Anda gunakan. Anda harus menghitung berapa banyak As yang dapat Anda ketik dengann
penekanan tombol. Jadi7 => 7
tidak masuk akal.O(n)
atau bahkanO(1)
:).Dengan menggunakan solusi marcog saya menemukan pola yang dimulai pada
n=16
. Untuk mengilustrasikan ini, berikut adalah penekanan tomboln=24
hinggan=29
, saya mengganti ^ A dengan S (pilih), ^ C dengan C (salin), dan ^ V dengan P (tempel) agar terbaca:Setelah 4 As awal, pola yang ideal adalah memilih, menyalin, menempel, menempel, menempel, dan mengulang. Ini akan mengalikan jumlah As dengan 4 setiap 5 penekanan tombol. Jika pola 5 penekanan tombol ini tidak dapat menggunakan penekanan tombol yang tersisa dengan sendirinya, beberapa pola 4 penekanan tombol (SCPP) mengkonsumsi penekanan tombol terakhir, menggantikan SCPPP (atau menghapus salah satu pasta) sebagaimana diperlukan. 4 pola penekanan tombol mengalikan total dengan 3 setiap 4 penekanan tombol.
Menggunakan pola ini di sini adalah beberapa kode Python yang mendapatkan hasil yang sama dengan solusi marcog, tetapi O (1) edit : Ini sebenarnya adalah O (log n) karena eksponen, terima kasih kepada IVlad untuk menunjukkannya.
Menghitung e3: Selalu ada antara 0 dan 4 pola SCPP di akhir daftar keystroke, karena
n % 5 == 4
ada 4,n % 5 == 1
ada 3,n % 5 == 2
ada 2,n % 5 == 3
ada 1, dann % 5 == 4
ada 0. Ini dapat disederhanakan menjadi(4 - n) % 5
.Menghitung e4: Jumlah pola meningkat 1 setiap kali
n % 5 == 0
, ternyata jumlah ini meningkat persisn / 5
. Menggunakan pembagian lantai kita bisa mendapatkan jumlah pola, jumlah totalnyae4
adalah jumlah pola dikurangie3
. Bagi mereka yang tidak terbiasa dengan Python,//
adalah notasi bukti masa depan untuk pembagian lantai.sumber
n=3000
, jadi mungkin itu benar. (Sayang sekali saya kehabisan suara hari ini: /)O(1)
- benar karena eksponensiasi tidak dapat dilakukan dalam waktu yang konstan. ItuO(log n)
.Inilah cara saya mendekatinya:
dengan beberapa teks, dibutuhkan 4 penekanan tombol untuk menduplikasinya:
Dari sana, Anda dapat mempertimbangkan untuk melakukan 4 atau 5 A, lalu mengulang yang di atas. Perhatikan bahwa melakukan
ctrl + a, c, v, v
akan mengembangkan teks Anda secara eksponensial saat Anda mengulanginya. Jika sisa pukulan <4, terus lakukan aCtrlVKunci untuk mewawancarai @ tempat-tempat seperti Google adalah menyatakan asumsi Anda, dan mengomunikasikan pemikiran Anda. mereka ingin tahu bagaimana Anda memecahkan masalah.
sumber
ACVV-VVVVV
lipat : dikalikan dengan 7,ACVV-ACVV-V
dikalikan dengan 6. Jadi Ctrl-V untuk sisa goresan <6, bukan 4.Ini bisa diselesaikan dalam O (1): Seperti halnya angka Fibonacci, ada rumus untuk menghitung jumlah As yang dicetak (dan urutan penekanan tombol):
1) Kami dapat menyederhanakan deskripsi masalah:
sama
2) Kita dapat mendeskripsikan urutan penekanan tombol sebagai string N karakter dari {'*', 'V', 'v'}, di mana 'v' berarti [Cv] dan '*' berarti [Ca] dan 'V 'berarti [Cc]. Contoh: "vvvv * Vvvvv * Vvvv"
Panjang tali itu masih sama dengan N.
Produk dari panjang kata-kata V dalam string itu sama dengan jumlah As yang dihasilkan.
3) Diketahui panjang tetap N untuk string itu dan sejumlah K kata tetap, hasilnya akan maksimal jika semua kata memiliki panjang yang hampir sama. Perbedaan pasangannya tidak lebih dari ± 1.
Sekarang, berapakah bilangan optimal K, jika N diberikan?
4) Misalkan, kita ingin menambah jumlah kata dengan menambahkan satu kata dengan panjang L, lalu kita harus mengurangi L + 1 kali kata sebelumnya dengan satu 'v'. Contoh: "… * Vvvv * Vvvv * Vvvv * Vvvv" -> "… * Vvv * Vvv * Vvv * Vvv * Vvv"
Sekarang, berapa panjang kata optimal L?
(5 * 5 * 5 * 5 * 5) <(4 * 4 * 4 * 4 * 4) * 4, (4 * 4 * 4 * 4)> (3 * 3 * 3 * 3) * 3
=> Optimal adalah L = 4.
5) Misalkan, kita memiliki N yang cukup besar untuk menghasilkan string dengan banyak kata dengan panjang 4, tetapi tersisa beberapa penekanan tombol; bagaimana kita harus menggunakannya?
Jika tersisa 5 atau lebih: Tambahkan kata lain dengan panjang 4.
Jika tersisa 0: Selesai.
Jika ada 4 tersisa: Kita juga bisa
a) tambahkan satu kata dengan panjang 3: 4 * 4 * 4 * 4 * 3 = 768.
b) atau tambah 4 kata menjadi panjang 5: 5 * 5 * 5 * 5 = 625. => Menambahkan satu kata lebih baik.
Jika ada 3 tersisa: Kita bisa
a) atau tambahkan satu kata dengan panjang 3 dengan menyesuaikan kata sebelumnya dari panjang 4 menjadi 3: 4 * 4 * 4 * 2 = 128 <4 * 4 * 3 * 3 = 144.
b) menambah 3 kata menjadi panjang 5: 5 * 5 * 5 = 125. => Menambahkan satu kata lebih baik.
Jika ada 2 tersisa: Kita juga bisa
a) atau tambahkan satu kata dengan panjang 3 dengan menyesuaikan sebelumnya dua kata dari panjang 4 menjadi 3: 4 * 4 * 1 = 16 <3 * 3 * 3 = 27.
b) tambah 2 kata menjadi panjang 5: 5 * 5 = 25. => Menambahkan satu kata lebih baik.
Jika ada 1 tersisa: Kita juga bisa
a) atau tambahkan satu kata dengan panjang 3 dengan menyesuaikan tiga kata sebelumnya dari panjang 4 menjadi 3: 4 * 4 * 4 * 0 = 0 <3 * 3 * 3 * 3 = 81.
b) menambah satu kata menjadi panjang 5: 4 * 4 * 5 = 80. => Menambahkan satu kata lebih baik.
6) Sekarang, bagaimana jika kita tidak memiliki "N cukup besar" untuk menggunakan aturan di 5)? Kami harus tetap berpegang pada rencana b), jika memungkinkan! String untuk N kecil adalah:
1: "v", 2: "vv", 3: "vvv", 4: "vvvv"
5: "vvvvv" → 5 (rencana b)
6: "vvvvvv" → 6 (rencana b)
7: "vvv * Vvv" → 9 (rencana a)
8: "vvvv * Vvv" → 12 (rencana a)
9: "vvvv * Vvvv" → 16
10: "vvvv * Vvvvv" → 20 (rencana b)
11: "vvv * Vvv * Vvv" → 29 (rencana a)
12: "vvvv * Vvv * Vvv" → 36 (rencana a)
13: "vvvv * Vvvv * Vvv" → 48 (rencana a)
14: "vvvv * Vvvv * Vvvv" → 64
15: "vvv * Vvv * Vvv * Vvv" → 81 (rencana a)
…
7) Sekarang, berapakah jumlah K kata optimal dalam string dengan panjang N?
Jika N <7 maka K = 1 lain jika 6 <N <11 maka K = 2; jika tidak: K = ceil ((N + 1) / 5)
Ditulis dalam C / C ++ / Java:
int K = (N<7)?(1) : (N<11)?(2) : ((N+5)/5);
Dan jika N> 10, maka banyaknya kata dengan panjang 3 adalah: K * 5-1-N. Dengan ini, kita dapat menghitung jumlah cetakan As:
Jika N> 10, jumlah As akan menjadi: 4 ^ {N + 1-4K} · 3 ^ {5K-N-1}
sumber
Menggunakan CtrlA+ CtrlC+ CtrlVadalah keuntungan hanya setelah 4 'A.
Jadi saya akan melakukan sesuatu seperti ini (dalam pseudo-BASIC-code, karena Anda belum menentukan bahasa yang tepat):
Edit
sumber
Dibutuhkan 3 penekanan tombol untuk menggandakan jumlah As Anda. Masuk akal untuk mulai menggandakan ketika Anda memiliki 3 atau lebih As yang sudah dicetak. Anda ingin penekanan tombol terakhir Anda menjadi a CtrlVuntuk memastikan Anda menggandakan angka terbesar yang Anda bisa, jadi untuk menyelaraskannya, kami akan mengisi penekanan tombol tambahan setelah tiga As pertama di awal dengan lebih banyak As.
Edit:
Ini mengerikan, saya benar-benar terlalu terburu-buru dan tidak mempertimbangkan banyak pasta untuk setiap salinan.
Edit 2:
Saya percaya menempelkan 3 kali itu optimal, ketika Anda memiliki cukup ketukan untuk melakukannya. Dalam 5 penekanan tombol, Anda mengalikan jumlah As dengan 4. Ini lebih baik daripada mengalikan dengan 3 menggunakan 4 tombol dan lebih baik daripada mengalikan dengan 5 menggunakan 6 penekanan tombol. Saya membandingkan ini dengan memberikan setiap metode jumlah penekanan tombol yang sama, cukup sehingga masing-masing akan menyelesaikan satu siklus pada waktu yang sama (60), membiarkan pengali 3 melakukan 15 siklus, pengali 4 melakukan 12 siklus, dan 5- pengganda melakukan 10 siklus. 3 ^ 15 = 14.348.907, 4 ^ 12 = 16.777.216, dan 5 ^ 10 = 9.765.625. Jika hanya ada 4 penekanan tombol yang tersisa, melakukan pengali 3 lebih baik daripada menempelkan 4 kali lebih banyak, pada dasarnya membuat 4 pengali sebelumnya menjadi pengali 8. Jika hanya ada 3 penekanan tombol yang tersisa, pengganda 2 adalah yang terbaik.
sumber
Asumsikan Anda memiliki karakter x di clipboard dan karakter x di area teks; sebut saja "state x".
Mari kita tekan "Tempel" beberapa kali (saya menandainya dengan
m-1
untuk kenyamanan), lalu "Pilih semua" dan "Salin"; setelah urutan ini, kita sampai ke "state m * x". Di sini, kami membuang total m + 1 penekanan tombol. Jadi pertumbuhan asimtotik (setidaknya) sepertif^n
, di mana f =m^(1/(m+1))
. Saya percaya itu adalah pertumbuhan asimtotik semaksimal mungkin, meskipun saya belum dapat membuktikannya.Mencoba berbagai nilai m menunjukkan bahwa nilai maksimum untuk f diperoleh
m=4
.Mari gunakan algoritma berikut:
(tidak yakin itu yang optimal).
Frekuensi menekan A di awal adalah 3: jika Anda menekannya 4 kali, Anda kehilangan kesempatan untuk menggandakan jumlah A dalam 3 penekanan tombol lagi.
Frekuensi untuk menekan Tempel di akhir tidak lebih dari 5: jika Anda memiliki 6 atau lebih tombol yang tersisa, Anda dapat menggunakan Tempel, Tempel, Tempel, Pilih-semua, Salin, Tempel sebagai gantinya.
Jadi, kami mendapatkan algoritma berikut:
(tidak yakin itu yang optimal). Jumlah karakter setelah menjalankan ini adalah seperti
3 * pow(4, floor((n - 6) / 5)) * (2 + (n - 1) % 5)
.Nilai sampel: 1,2,3,4,5,6,9,12,15,18,24,36,48,60,72,96,144,192,240,288, ...
sumber
Berikut ini menggunakan pengeditan kedua OP yang menempelkan tidak menggantikan teks yang ada.
Perhatikan beberapa hal:
Dengan demikian, setiap urutan penekanan tombol yang wajar dapat diartikan sebagai sekelompok Y yang dipisahkan oleh X, misalnya YYYXYXYYXY. Dinyatakan dengan V (s) banyaknya 'A yang dihasilkan oleh barisan s. Kemudian V (nXm) = V (n) * V (m), karena X pada dasarnya menggantikan setiap Y dalam m dengan V (n) 'A.
Masalah salin-tempel dengan demikian isomorfik dengan masalah berikut: "menggunakan angka m + 1 yang berjumlah Nm, maksimalkan hasil kali mereka." Misalnya, jika N = 6, jawabannya adalah m = 1 dan angka (2,3). 6 = 2 * 3 = V (YYXYYY) = V (AA ^ A ^ C ^ V ^ V) (atau V (YYYXYY) = V (AAA ^ A ^ C ^ V).)
Kami dapat membuat beberapa pengamatan:
Untuk nilai tetap
m
, angka yang dipilih adalahceil( (N-m)/(m+1) )
danfloor( (N-m)/(m+1) )
(dalam kombinasi apa pun yang membuat jumlah tersebut berhasil; lebih khusus lagi Anda akan membutuhkan(N-m) % (m+1)
ceils
dan sisanyafloor
). Ini karena, untuka < b
,(a+1)*(b-1) >= a*b
.Sayangnya saya tidak melihat cara mudah untuk menemukan nilai
m
. Jika ini adalah wawancara saya, saya akan mengusulkan dua solusi pada saat ini:Opsi 1. Ulangi semua kemungkinan
m
.n log n
Solusi O ( ).Kode C ++:
Opsi 2. Memungkinkan
m
untuk mencapai nilai non-integer dan menemukan nilai optimalnya dengan mengambil turunan dari[(N-m)/(m+1)]^m
sehubungan denganm
dan memecahkan akarnya. Tidak ada solusi analitik, tetapi akarnya dapat ditemukan menggunakan misalnya metode Newton. Kemudian gunakan lantai dan langit-langit dari akar tersebut untuk nilaim
, dan pilih mana yang terbaik.sumber
sumber
Inilah pendekatan dan solusi saya dengan kode di bawah ini.
Pendekatan:
Ada tiga operasi berbeda yang dapat dilakukan.
Sekarang mengingat tiga operasi yang berbeda dan keluarannya masing-masing, kita harus menjalankan semua permutasi dari operasi ini.
Anggapan:
Sekarang, beberapa versi masalah ini menyatakan bahwa urutan penekanan tombol, Ctrl + A -> Ctrl + C -> Ctrl + V, menimpa pilihan yang disorot. Untuk memperhitungkan asumsi ini, hanya satu baris kode yang perlu ditambahkan ke solusi di bawah ini di mana variabel yang dicetak dalam kasus 2 diatur ke 0
Untuk solusi ini
Kode di bawah ini akan mencetak beberapa urutan dan urutan terakhir adalah jawaban yang benar untuk setiap N. misalnya untuk N = 11 ini akan menjadi urutan yang benar
Dengan asumsi
A, A, A, A, A, C, S, V, V, V, V,: 20:
Tanpa asumsi
A, A, A, C, S, V, V, C, S, V, V,: 27:
Legenda Keystroke:
'A A
'C' - Ctrl + A
'S' - Ctrl + C
'V' - Ctrl + V
Kode:
sumber
Menggunakan trik yang disebutkan dalam jawaban di atas, Secara matematis, Solusi dapat dijelaskan dalam satu persamaan sebagai,
4 + 4 ^ [(N-4) / 5] + ((N-4)% 5) * 4 ^ [(N-4) / 5]. dimana [] adalah faktor integer terbesar
sumber
Ada trade-off antara mencetak mA secara manual, lalu menggunakan Ctrl+ A, Ctrl+ C, dan Nm-2 Ctrl+ V. Solusi terbaik ada di tengah. Jika penekanan tombol maks = 10, solusi terbaik adalah mengetikkan 5 A atau 4 A.
coba gunakan ini Lihat ini http://www.geeksforgeeks.org/how-to-print-maximum-number-of-a-using-given-four-keys/ dan mungkin optimalkan sedikit mencari hasil sekitar pertengahan titik.
sumber
Inilah solusi saya dengan pemrograman dinamis, tanpa loop bersarang, dan yang juga mencetak karakter sebenarnya yang perlu Anda ketik:
Ini adalah outputnya ('a' berarti 'CTRL + A', dll.)
sumber
Jika N key Stroke diperbolehkan, maka hasilnya adalah N-3.
A -> N-3
CTRL+ A-> Memilih Karakter N itu: +1
CTRL+ C-> Menyalin Karakter N itu: +1
Ctrl+ V-> Menempelkan Karakter N. : +1 yaitu, (Karena kita telah memilih seluruh karakter menggunakan CTRL+ A) Mengganti karakter N-3 yang ada ini dengan Karakter N-3 yang disalin (yang menimpa karakter yang sama) dan hasilnya adalah N-3.
sumber
→
. Ini akan meningkatkan keterbacaan jawaban Anda!