雞鴨分類(類雙指針)
題目描述:
農場有n只雞鴨排爲一個隊伍,雞用“C”表示,鴨用“D”表示。當雞鴨挨着時會產生矛盾。需要對所排的隊伍進行調整,使雞鴨各在一邊。每次調整隻能讓相鄰的雞和鴨交換位置,現在需要儘快完成隊伍調整,你需要計算出最少需要調整多少次可以讓上述情況最少。例如:CCDCC->CCCDC->CCCCD這樣就能使之前的兩處雞鴨相鄰變爲一處雞鴨相鄰,需要調整隊形兩次。
輸入描述:
輸入一個長度爲N,且只包含C和D的非空字符串。
輸出描述:
使得最後僅有一對雞鴨相鄰,最少的交換次數。
思路:
交換最後得到的結果只有兩種,雞左鴨右,鴨左雞右
在代碼中可以把‘C’都全移到左邊或者把‘D’全移到左邊,去最小者即可
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
cin >> s;
int count = 0;
int sumC = 0;
int sumD = 0;
// 把C往左移
for(int i = 0; i<s.size(); i++)
{
if(s[i] == 'C'){ //單引號
sumC += i-count++; //********
}
}
// 把D往左移
count = 0; //重置
for(int i = 0; i < s.size(); i++)
{
if(s[i] == 'D'){
sumD += i-count++; //********
}
}
cout << min(sumC, sumD) << endl;
return 0;
}
其中count計數這是第幾個c/d(從0開始)i-count爲第i個字符需要移動的個數
輸入:cin>>“CCDCC”
C左移:
i=0,s[1]=c,sumc=0+0-0;
i=1,s[1]=c,sumc=0+1-1;
i=2,s[2]=d;
i=3,s[3]=c,sumc=0+3-2;
i=4,s[4]=c,sumc=1+4-3=2;
D左移:
i=0,s[1]=c;
i=1,s[1]=c;
i=2,s[2]=d,sumd=0+2-0=2;
i=3,s[3]=c;
i=4,s[4]=c;
輸出:cout<<2
比特幣最佳買賣時間
題目描述:
給定一個正整數數組,它的第 i 個元素是比特幣第 i 天的價格。
如果你最多隻允許完成一筆交易(即買入和賣出一次),設計一個算法來計算你所能獲取的最大利潤。注意你不能在買入比特幣前賣出。
輸入描述:
正整數數組,爲以空格分隔的n個正整數
輸出描述:
最大利潤
C++中cin的詳細用法
ctrl+z結束
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, mi = INT_MAX, maxProfit = 0;
while(cin >> n) { //*****
maxProfit = max(n - mi, maxProfit);
mi = min(n, mi);
}
cout << maxProfit;
return 0;
}
import java.util.Scanner;
import java.util.ArrayList;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
ArrayList<Integer> coin=new ArrayList<>();
while(in.hasNextInt()){
coin.add(in.nextInt());
}
Integer[] co=new Integer[coin.size()];
coin.toArray(co);
int profit=0;
for(int i=co.length-1;i>=0;i--)
for(int j=0;j<i;j++){
profit=Math.max((co[i]-co[j]),profit);
}
System.out.println(profit);
}
}
愛喫喵糧的小貓(貪心)
題目描述:
小招喵喜歡喫喵糧。這裏有 N 堆喵糧,第 i 堆中有 p[i] 粒喵糧。喵主人離開了,將在 H 小時後回來。
小招喵可以決定她喫喵糧的速度 K (單位:粒/小時)。每個小時,她將會選擇一堆喵糧,從中喫掉 K 粒。如果這堆喵糧少於 K 粒,她將喫掉這堆的所有喵糧,然後這一小時內不會再喫更多的喵糧。
小招喵喜歡慢慢喫,但仍然想在喵主人回來前喫掉所有的喵糧。返回她可以在 H 小時內喫掉所有喵糧的最小速度 K(K 爲整數)。
輸入描述:
第一行輸入爲喵糧數組,以空格分隔的N個整數
第二行輸入爲H小時數
輸出描述:
最小速度K
貪心 + 二分查找
理論最小進食速度: 所有喵糧求和 / 給定的小時數
理論最大進食速度:最大堆的喵糧數
在這兩個之間二分查找最小實際可行進食速度即可
注:這是一個lower_bound的二分問題,即求最左邊滿足條件的值 需要相應修改二分查找
#include <bits/stdc++.h>
using namespace std;
vector<int> arr;
int H, tmp, sum = 0, res, mmax = 0, mmin;
bool solve(int x, int H) {//x爲速度
int res = 0;//喫完所有貓糧所需時間
for(int i = 0; i < arr.size(); i++) {
res += (arr[i] % x == 0) ? arr[i] / x: arr[i] / x + 1;
}
return res <= H;
}
int main() {
string line; getline(cin, line);
istringstream iss(line);
while(iss >> tmp) {
arr.push_back(tmp);
mmax = max(mmax, tmp);
sum += tmp;
}
scanf("\n%d", &H);
mmin = (sum % H == 0) ? sum / H : sum / H + 1; //理論min
while(mmin < mmax) { //二分查找終止條件
res = (mmin + mmax) / 2;
if(solve(res, H)) mmax = res;//滿足條件時 將右邊屆設爲中間值
else mmin = res + 1;
if(solve(mmin, H)) break;//左邊界滿足時 終止
}
cout<<mmin<<endl;//結果爲左邊界
}
#include <bits/stdc++.h>
using namespace std;
int main(){
int x,h;
vector<int> p;
while(cin>>x)
p.push_back(x);
int n = p.size()-1;
h = p[n]; //****關於輸入的處理
int k = 1, t;
do{
t = 0;
for(int i=0;i<n;i++)
t += ceil(1.0*p[i]/k);
k++;
}while(t>h);
cout<<k-1<<endl;
return 0;
}
x遊戲
題目描述:
我們稱一個數 X 爲好數, 如果它的每位數字逐個地被旋轉 180 度後,我們仍可以得到一個有效的,且和 X 不同的數。要求每位數字都要被旋轉。
如果一個數的每位數字被旋轉以後仍然還是一個數字, 則這個數是有效的。0, 1, 和 8 被旋轉後仍然是它們自己;2 和 5 可以互相旋轉成對方;6 和 9 同理,除了這些以外其他的數字旋轉以後都不再是有效的數字。
現在我們有一個正整數 N, 計算從 1 到 N 中有多少個數 X 是好數?
輸入描述:
輸入正整數N
輸出描述:
輸出1到N中好數個數
C++中int與string的相互轉換
#include <bits/stdc++.h>
using namespace std;
bool isGood(int i){
string s = to_string(i);
string rotate;/////****
for(int j=0;j<s.length();j++){
if(s[j] == '0' || s[j] == '1' || s[j] == '8'){
rotate[j] = s[j];continue;
}
if(s[j] == '2'){
rotate[j] = '5';continue;
}
if(s[j] == '5'){
rotate[j] = '2';continue;
}
if(s[j] == '6'){
rotate[j] = '9';continue;
}
if(s[j] == '9'){
rotate[j] = '6';continue;
}
else{
return false;
}
}
int after_rotate = atoi(rotate.c_str());
if(i == after_rotate){
return false;
}
return true;
}
int main(){
int n,count = 0;
cin>>n;
for(int i=1;i<=n;i++){
if(isGood(i)){
count++;
}
}
cout<<count<<endl;
return 0;
}
跳格子游戲
題目描述:
假設你正在玩跳格子(所有格子排成一個縱列)遊戲。需要 跳完n 個格子你才能抵達終點。
每次你可以跳 1 或 2 個格子。你有多少種不同的方法可以到達終點呢?
注意:給定 n 是一個正整數。
輸入描述:格子數n
輸出描述:跳完n個格子到達終點的方法
狀態轉移公式:
當前階梯可以由前一級階梯跳一級到達,也可由前兩級階梯跳兩級到達。
#include <iostream>
using namespace std;
int main(){
int n;
cin>>n;
int dp[n] = {0};
dp[0] = 1;
dp[1] = 2;
for(int i=2;i<n;i++){
dp[i] = dp[i-1] + dp[i-2];
}
cout<<dp[n-1]<<endl;
return 0;
}
糖果分配(動態規劃)
題目描述:
假設你是一位很有愛的幼兒園老師,想要給幼兒園的小朋友們一些小糖果。但是,每個孩子最多隻能給一塊糖果。對每個孩子 i ,都有一個胃口值 gi ,這是能讓孩子們滿足胃口的糖果的最小尺寸;並且每塊糖果 j ,都有一個尺寸 sj 。如果 sj >= gi ,我們可以將這個糖果 j 分配給孩子 i ,這個孩子會得到滿足。你的目標是儘可能滿足越多數量的孩子,並輸出這個最大數值。
注意:
你可以假設胃口值爲正。
一個小朋友最多隻能擁有一塊糖果。
輸入描述:
第一行輸入每個孩子的胃口值
第二行輸入每個糖果的尺寸
孩子數和糖果數不超過1000
輸出描述:
能滿足孩子數量的最大值
sort函數對vector容器進行排序
#include <bits/stdc++.h>
using namespace std;
int main(){
string S;
vector<int> g,s;
getline(cin, S);
stringstream ss1(S);
int x, cnt=0;
while(ss1>>x)
g.push_back(x);
getline(cin, S);
stringstream ss2(S);
while(ss2>>x)
s.push_back(x);
sort(g.begin(), g.end());
sort(s.begin(), s.end());
for(int i=0,j=0;i<g.size() && j<s.size();){
if(g[i]<=s[j]){
cnt++;
i++;
j++;
}else
j++;
}
cout<<cnt<<endl;
return 0;
}
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int num;
vector<int> g;
vector<int> s;
while(cin>>num)
{
g.push_back(num);
if(getchar()=='\n') //*****
break;
}
while(cin>>num)
{
s.push_back(num);
if(getchar()=='\n')
break;
}
sort(g.begin(),g.end());//****
sort(s.begin(),s.end());
int sum=0;
for(int i=0,j=0;j<s.size();j++)
{
if(i>=g.size())
break;
if(s[j]>=g[i])
{
sum++;
i++;
}
}
cout<<sum;
}
員工考勤記錄(斐波那契)
題目描述:
給定一個字符串來代表一個員工的考勤紀錄,這個紀錄僅包含以下兩個字符:
‘A’ : Absent,缺勤
‘P’ : Present,到場
如果一個員工的考勤紀錄中不超過兩個’A’(缺勤),那麼這個員工會被獎賞。
如果你作爲一個員工,想在連續N天的考勤週期中獲得獎賞,請問有多少種考勤的組合能夠滿足要求
輸入描述:
考勤週期的天數N(正整數)
輸出描述:
這N天裏能獲得獎賞的考勤組合數
#include <bits/stdc++.h>
using namespace std;
int cal(int n){
if(n==2){
return 1;
}
else{
return (cal(n-1)+n-1);
}
}
int main(){
int n,count;
cin>>n;
count = n + 1 + cal(n);
cout<<count<<endl;
return 0;
}
總結目前牛客問題 :
第一,沒有循環輸入問題,
第二 有循環輸入問題,
第三 輸入有多餘空格問題 ,
第四 中間插入多餘空行問題 …
解碼方法(**動態規劃)
題目描述:
一條包含字母 A-Z 的消息通過以下方式進行了編碼:
‘A’ -> 1
‘B’ -> 2
…
‘Z’ -> 26
給定一個只包含數字的非空字符串,請計算解碼方法的總數。
輸入描述:
12可以解碼成“AB”,“L”這兩種
輸出描述:
解碼方法的總數
#include <iostream>
using namespace std;
int main(void){
string s;
int len;
cin>>s;
len = s.length();
int *dp = new int[len+1]{};
dp[0] = 1;
for(int i = 1; i <= len; ++i){
if(s[i-1] != '0')
dp[i] += dp[i-1];
if(i >= 2 && s[i-2] == '1' || s[i-2] == '2' && s[i-1] < '7')
dp[i] += dp[i-2];
}
cout<<dp[len]<<endl;
delete dp;
return 0;
}
s = input()
n = len(s)
x_1 = 1
for i in range(n):
if i == 0:
x_2 = 1
else:
if int(s[i - 1: i + 1]) <= 26:
x_1, x_2 = x_2, x_1 + x_2
else:
x_1 = x_2
print(x_2)
漂流船問題(雙指針)
題目描述:
公司組織團建活動,到某漂流聖地漂流,現有如下情況:
員工各自體重不一,第 i 個人的體重爲 people[i],每艘漂流船可以承載的最大重量爲 limit。
每艘船最多可同時載兩人,但條件是這些人的重量之和最多爲 limit。
爲節省開支,麻煩幫忙計算出載到每一個人所需的最小船隻數(保證每個人都能被船載)。
輸入描述:
第一行輸入參與漂流的人員對應的體重數組,
第二行輸入漂流船承載的最大重量
輸出描述:
所需最小船隻數
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int num,limit;
vector<int> people;
while(cin>>num){
people.push_back(num);
if(getchar() == '\n'){
break;
}
}
cin>>limit;
sort(people.begin(),people.end());
int boat = 0;
int i = 0;
int j = people.size()-1;
while(i<j){
if(people[i] + people[j] <= limit){
i++;
j--;
}
else{
j--;
}
boat++;
}
if(i == j){
boat++;
}
cout<<boat<<endl;
return 0;
}
**推倒吧骨牌
題目描述:
輸入描述:
輸入爲一個長度不超過1000的,僅包含‘L’,‘R’,‘.’的字符串
輸出描述:
根據輸入,輸出一個僅由‘L’,‘R’,‘.’組成的結果字符串
思路:
從這往右遍歷,用flag記錄之前是否有右傾;用pos記錄上次右傾位置;
遍歷無非兩種情況:
當前是左傾:1.在最左側,直接往左邊倒完。2.前面存在右傾:相擁而倒;
當前是右傾:1.前面有右傾:處理前面的右傾,更新pos;2:前面無右傾,設置flag和pos;
遍歷結束後再處理是否有最後殘留的那個flag;
#include<iostream>
#include<string>
using namespace std;
int main()
{
string data;
while(cin>>data)
{
int rflag=0;
int pos;
int len=data.size();
for(int i=0;i<len;i++)
{
if(data[i]=='L')
{
int cur=i-1;
if(rflag==0)
{
while(cur>=0&&data[cur]=='.')
{
data[cur]='L';cur--;
}
}
else
{
int l=pos+1;
while(cur>l)
{
data[cur]='L';
data[l]='R';
l++;cur--;
}
rflag=0;
}
}
if(data[i]=='R')
{
if(rflag==0)
{
rflag=1;
pos=i;
}
else{
pos=i;
int cur=i-1;
while(cur>=0&&data[cur]=='.')
{
data[cur]='R';cur--;
}
}
}
}
if(rflag)
{
int cur=pos+1;
while(cur<len)
{
data[cur]='R';
cur++;
}
}
cout<<data<<endl;
}
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
char[] chs = scanner.next().toCharArray();
int len = chs.length;
int[] values = new int[len];
// 第一遍從左往右遍歷,遇到R就賦值length,接下來如果是.則遞減,直到遇到L清零
int value = 0;
for (int i = 0; i < len; i++) {
if (chs[i] == 'R') {
value = len;
} else if (chs[i] == 'L') {
value = 0;
} else {
// 保證L之後遇到.仍舊賦值0而不是負數
value = Math.max(value - 1, 0);
}
// values數組加上value值
values[i] += value;
}
// 第二遍從右往左遍歷,遇到L就賦值length,接下來如果是.則遞減,直到遇到R清零
value = 0;
for (int i = len - 1; i >= 0; --i) {
if (chs[i] == 'L') {
value = len;
} else if (chs[i] == 'R') {
value = 0;
} else {
// 保證R之後遇到.仍舊賦值0而不是負數
value = Math.max(value - 1, 0);
}
// values數組減去value值
values[i] -= value;
}
StringBuilder result = new StringBuilder();
// values值大於0則爲R,小於0則爲L,等於0則爲.
for (int i : values) {
result.append(i > 0 ? 'R' : i < 0 ? 'L' : '.');
}
System.out.println(result);
}
}
"""
LR匹配問題,記錄之前方向,分4類討論LL/RL/RR/LR
"""
import math
if __name__ == "__main__":
s = list(input().strip())
ans = s[:]
t = pl = pr = 0
flag = '0'
while t < len(s):
while t < len(s) and s[t] == '.': t += 1
if t >= len(s): break
if s[t] == 'L':
if flag == '0' or flag == 'L':
for i in range(pl, t):
ans[i] = 'L'
else:
pl = t
for i in range(pr, math.ceil((pr + pl) / 2)):
ans[i] = 'R'
for i in range(math.floor((pr + pl) / 2) + 1, pl):
ans[i] = 'L'
flag = 'L'
elif s[t] == 'R':
if flag == 'R':
for i in range(pr + 1, t):
ans[i] = 'R'
pr = t
flag = 'R'
t += 1
if pr > pl:
for i in range(pr, len(s)):
ans[i] = 'R'
print(''.join(ans))