首页 > 试题广场 >

红和绿

[编程题]红和绿
  • 热度指数:7537 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
牛牛有一些排成一行的正方形。每个正方形已经被染成红色或者绿色。牛牛现在可以选择任意一个正方形然后用这两种颜色的任意一种进行染色,这个正方形的颜色将会被覆盖。牛牛的目标是在完成染色之后,每个红色R都比每个绿色G距离最左侧近。牛牛想知道他最少需要涂染几个正方形。
如样例所示: s = RGRGR
我们涂染之后变成RRRGG满足要求了,涂染的个数为2,没有比这个更好的涂染方案。

输入描述:
输入包括一个字符串s,字符串s长度length(1 ≤ length ≤ 50),其中只包括'R'或者'G',分别表示红色和绿色。


输出描述:
输出一个整数,表示牛牛最少需要涂染的正方形数量
示例1

输入

RGRGR

输出

2
用枚举,以每一个点为起点,左边的 都是R,右边的都是G,记录每一次的次数,排序,得到最小的
发表于 2019-02-13 10:45:13 回复(0)

python两行

暴力枚举的,感觉不够优雅。

每个位置都试一遍,假设为红与绿的分界点,在这些结果里面找到最小值。

例如对于位置i,左边全部要染成红色,右边全部要染成绿色,则当前的值为s[:i].count('G') + s[i:].count('R')

代码如下:

s = input()
print(min(map(lambda i: s[:i].count('G') + s[i:].count('R'), range(0, len(s) + 1))))
发表于 2019-03-15 22:00:39 回复(2)
代码思路:将每一个元素看做中点,左边的涂成R,右边的涂成G,找到涂染个数,在多个涂染个数中找到最小的那个,输出。
var str = readline()
var res = 1000
for (var i = 0; i < str.length; i++) {
    count = 0;
    for (var j = 0; j < i; j++) {
        if (str[j] != 'R') count++
    }
    for (var j = i; j < str.length; j++) {
        if (str[j] != 'G') count++
    }
    res = res < count ? res : count
}
console.log(res)
发表于 2017-12-06 18:38:56 回复(1)
s=input()
res=[]
for i in range(len(s)):
    res.append(s[:i].count('G')+s[i:].count('R'))
print(min(res))

发表于 2019-03-31 15:16:44 回复(1)
显然,我们要保证前面都是红色,后面都是绿色,问题就是前面有多少个红色能使得染色的次数最少。遍历所有的分割点可能性[0,str.length()-1],计算在每种情况下的染色次数,输出最小的即可。
s = input()
# 分别将[0,len(s)-1]作为最后一个red的位置,计算在这些分割点下染色的最小次数
print(min([s[:i].count('G') + s[i:].count('R') for i in range(len(s))]))
而为了不用每次都遍历分割点左边的绿和右边的红,可以先用两个辅助数组记录一下,用到的时候直接查表
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str = br.readLine().trim();
        int n = str.length();
        int[] green = new int[n];     // green[i]表示0~i有多少个G
        int[] red = new int[n];       // red[i]表示i~n-1有多少个R
        green[0] = str.charAt(0) == 'G'? 1: 0;
        red[n - 1] = str.charAt(n - 1) == 'R'? 1: 0;
        for(int i = 1; i < n; i++){
            green[i] = green[i - 1];
            if(str.charAt(i) == 'G') green[i]++;
        }
        for(int i = n - 2; i >= 0; i--){
            red[i] = red[i + 1];
            if(str.charAt(i) == 'R') red[i]++;
        }
        int minCount = n;
        for(int i = -1; i < n - 1; i++) minCount = Math.min(minCount, (i > -1? green[i]: 0) + red[i + 1]);
        System.out.println(minCount);
    }
}

编辑于 2021-11-22 14:04:42 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int cnt=0, green=0;
    string s;
    cin>>s;
    for(auto &c: s){
        if(c=='G')
            green++;
        else
            cnt = min(cnt+1, green);
    }
    printf("%d\n", cnt);
    return 0;
}

发表于 2020-10-11 01:12:38 回复(0)
动态规划 dp[i][2]:dp[i][0]代表前i个字符,以绿色结尾需要的最少的染色次数,dp[i][1]代表前i个字符,以红色结尾需要的最少染色次数。因为每次都要保证前i个字符中,要红色在左边,绿色在右边(可以全红,或者全绿),所以如果第i个以红色字符结尾,那么第i-1个字符一定是红色结尾;第i个字符以绿色结尾,第i-1个字符可以是红色也可以是绿色。 

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main()
{
    string src;
    cin >> src;
    int n = src.size();

    vector<vector<int>> dp(n + 1, vector<int>(2, 0));
    for (int i = 1; i <= n; ++i)
    {
        if ('G' == src[i-1])
        {
            dp[i][0] = min(dp[i - 1][0], dp[i - 1][1]);
            dp[i][1] = dp[i - 1][1] + 1;
        }
        else
        {
            dp[i][0] = min(dp[i - 1][0], dp[i - 1][1]) + 1;
            dp[i][1] = dp[i - 1][1];
        }
    }
    cout << min(dp[n][0], dp[n][1]) << endl;

    system("pause");
    return 0;
}
发表于 2019-10-08 13:55:45 回复(0)
//方法1:遍历一次数组,在当前位置为R时有可能两种情况,一种是把这个位置变成G,另一种是把前面的G全部变成R。
import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str = scan.nextLine();
        scan.close();
        int gCount = 0, count = 0;
        for(int i=0; i<str.length(); i++) {
            if(str.charAt(i)=='G') {
                gCount++;//记录G的个数
            }
            else {//如果当前字符是R
                count = Math.min(gCount, count+1);
            }//gCount表示把当前字符R前的所有G变成R,count表示当前字符R变成G
        }
        System.out.println(count);
    }
}

//方法2:用枚举,以每一个点为起点,左边的都是R,右边的都是G,记录每一次的次数,排序,得到最小的。
import java.util.Arrays;
import java.util.Scanner;
public class Main{
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str = scan.nextLine();
        scan.close();
        int[] count = new int[str.length()];//记录每一次枚举染色的次数
        for(int i=0; i<str.length(); i++) {
            for(int j=0; j<i; j++) {
                if(str.charAt(j)=='G') {
                    count[i]++;//若左边的是G,记录变成R的次数
                }
            }
            for(int j=i+1; j<str.length(); j++) {
                if(str.charAt(j)=='R') {
                    count[i]++;//若右边的是R,记录变成G的次数
                }
            }
        }
        Arrays.sort(count);
        System.out.println(count[0]);
    }
}
发表于 2019-06-12 20:58:23 回复(0)

  1. 思路:G遍历涂的个数 和 (R总 - 已遍历的个数) 的最小和
  2. 注意:左边全为G,右边全为R 的情况
  3. 时间复杂度O(n),空间复杂度O(1)
mystr = input()
mymin = Ry = Rcount = mystr.count('R')
GChangeCount = 0
for item in mystr:
    if item == 'G':
        GChangeCount +=1
    else:
        Rcount -=1
    if GChangeCount>=Ry and Ry == Rcount:
        mymin = Rcount
        break
    if Rcount+GChangeCount < mymin:
        mymin = Rcount+GChangeCount
    if Rcount == 0:
        break
print(mymin)


编辑于 2019-04-12 20:34:42 回复(0)
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<vector>
#include<math.h>
using namespace std;
int main(){
    string s;
    cin >> s;
    int countR = count(s.begin(), s.end(), 'R');
    int countG = count(s.begin(), s.end(), 'G');
    int frontG = 0;
    int frontR = 0;
    int numColor = 0;
    int minColor = s.size() + 1;
    //遇到红且是最后一个连续红就试试前面改成红,后面改成绿
    for(int i = 0; i < s.size(); ){
        if(s[i] == 'R'){
            while(i < s.size() && s[i] == 'R'){
                frontR++;
                i++;
            }
            //前面的绿色(染红) + 后面的红色(染绿)
            numColor = frontG + (countR - frontR);
            minColor = min(minColor, numColor);
        }
        else{
            frontG++;
            i++;
        }
    }
    cout << min(minColor, min(countR, countG)) << endl;
    
}

发表于 2019-03-03 21:20:55 回复(0)
#include<iostream>
#include<string>

using namespace std;

int main() {
    string s;
    cin >> s;
    int length = s.size();
    int ans = 50;
    for (int i = 0; i < length; i++) {
        int ans_temp = 0;
        for (int j = 0; j < length; j++) {
            if (s[j] == 'G' && j < i) ans_temp++;
            if (s[j] == 'R' && j >= i) ans_temp++;
        }
        if (ans_temp <= ans) ans = ans_temp;
    }
    cout << ans << endl;
   return 0;
}
发表于 2019-01-25 23:05:56 回复(0)

AC率这么低,我以为什么题,结果做了以后发现是个小学阅读理解题(题意描述不明)。

思路很简单,因为所有R要在G左边,所以枚举这个交接点就可以了。
import java.util.*;
public class Main {
    private static final int N_MAX = 55;
    private static final int INT_MAX= 0x3f3f3f3f;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        char[] in = sc.next().toCharArray();
        int[] counts = new int[N_MAX];
        for (int i=1; i<=in.length; i++) {
            if (in[i-1] == 'R') {
                counts[i] = counts[i-1] + 1;
            }
            else {
                counts[i] = counts[i-1];
            }
        }
        int ans = INT_MAX;
        for (int i=0; i<=in.length; i++) {
            int left  = i - counts[i];
            int right = counts[in.length] - counts[i];
            ans = Math.min(left+right, ans);
        }
        System.out.println(ans);
    }
}
发表于 2019-01-21 00:53:10 回复(0)
import java.util.*;
public class Main{
    public static void main(String[] args){
        try(Scanner in = new Scanner(System.in)){
            System.out.println(helper(in.nextLine()));
        }
    }
    public static int helper(String s){
        char[] a = s.toCharArray();
        int min = Integer.MAX_VALUE;
        for(int i = 0;i < a.length;i++){
            int s1 = 0,e1 = i,s2 = i,e2 = a.length,count = 0;
            while(s1 < e1){
                if(a[s1] == 'G') count++;
                s1++;
            }
            while(s2 < e2){
                if(a[s2] == 'R') count++;
                s2++;
            }
            min = Math.min(count,min);
        }
        return min;
    }
}


发表于 2019-01-18 16:16:19 回复(0)

各位大佬,这个测试用例结果为什么是3呢,难道不应该是最右边3个R涂为G,然后最左边三个G涂为R,这样算下来就是6次。如果按照答案来看的话那就是只把最右边三个涂为G,不保证和原来的R数一样。是这样理解吗
发表于 2018-03-20 20:27:16 回复(6)
#include<stdio.h>
#include<string.h>
#define min(a,b) a<b?a:b
int main(){
    char s[100];
    scanf("%s",s);
    int i,j,Min=1e8,n=strlen(s);
    for(i=0;i<n;i++){
        int cnt=0;
        for(j=0;j<i;j++) if(s[j]!='R') cnt++;
        for(j=i;j<n;j++) if(s[j]!='G') cnt++;
        Min=min(Min,cnt);
    }
    printf("%d\n",Min);
}

发表于 2017-11-28 23:16:39 回复(0)

我觉得我的方法简单,看大家很多是遍历所有可能的分界点做的,说一下我的方法,只需要遍历一次数组,
在当前位置为R时有可能两种情况,一种是吧这个位置编程G,另一种是吧前面的G全部变成R.

时间复杂度O(n),空间复杂度O(1) 
#include<bits/stdc++.h>
using namespace std;

int main()
{
    std::ios::sync_with_stdio(false);
    string s;
    cin >> s;
    int len = s.size();// 获取字符串长度
    int gCount = 0;// 字符串中G字母的个数
    int count = 0; // 最小涂色次数
    for(int i = 0; i < len;i++)
    {
        if(s[i] == 'G')
        {
            gCount++;
        }else
        {
            count = min(gCount, count + 1);
        }
            
    }
    cout << count << endl;
    return 0;
}

发表于 2019-02-27 18:40:28 回复(14)
DP。注意可以没有R或没有G。

s = input()
dp = [0] * (len(s) + 1)
dp[0] = s.count('R')
for i in range(len(s)):
    if s[i] == 'G':
        dp[i+1] = dp[i] + 1
    else:
        dp[i+1] = dp[i] - 1
print(min(dp))

发表于 2019-03-18 19:24:24 回复(0)
//红绿的数量不是固定的(不能用交换),所以是各种数量的讨论
//按顺序从左往右 
# include <iostream>

using namespace std;

int main(void)
{
    int i;
    int j;
    int n = 0;
    int red = 0; 
    int count = 0;
    int left;
    int right;
    char colors[51] = {'\0'};  //用C也能实现的方法
    
    cin >> colors;    
    for (i = 0; colors[i] != '\0'; i++)
    {
        if (colors[i] == 'R')
            red++;
        n++;
    }

    //从左往右  左边红色的数量不断增加
    i = 0;
    //全为绿的情况 
    left = 0;  //左边需要修改的数量 
    right = red;  //右边需要修改的数量 
    count = red; //一开始全绿,需要修改的数量 
    while (i < n)
    {
        if (colors[i] == 'R')
            right -= 1; //right需要修改的 减少一个 
        else
            left += 1;    //left需要修改的 增加一个     
        if (right + left < count)
        {
            count = right + left;
        }
        i++;
    
    
    cout << count << endl; 
    
    return 0;

发表于 2020-06-10 17:26:07 回复(0)
其实用一个temp存储遇到的g的数量,每遇一次+1,遇到了r就将temp赋值给count,最终输出count,就解决了,但是我自己在IDE上运行没错,不过提交总是说我错了,按照它的数据测试的
const readline = require('readline')

let count = 0
let str = ''
let r = readline.createInterface({
  input:process.stdin,
  output:process.stdout
})

new Promise(function (resolve,reject) {
  r.on('line',str=>{
    resolve(str)
  })
}).then(function (str) {
  for(let i = 0,temp = 0;i<str.length;i++){
    if(str[i] === 'G'){
      temp++
    }
    else{
      count = temp
    }
  }
  console.log(count)
})


发表于 2020-03-09 23:57:09 回复(0)
只要R的前面有一个G,就得涂一个
import java.util.*;
public class Main{
    private int getNum(String str){
        int num=0;
        int G=0;
        for(int i=0; i<str.length(); i++){
            if(str.charAt(i) == 'G')
                G ++;
            else if(G>0&&str.charAt(i)=='R'){
                G --;
                num ++;
            }
        }
        return num;
    }
}
发表于 2019-06-11 10:39:58 回复(0)