首页 > 试题广场 >

字符串价值

[编程题]字符串价值
  • 热度指数:563 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
有一种有趣的字符串价值计算方式:统计字符串中每种字符出现的次数,然后求所有字符次数的平方和作为字符串的价值
例如: 字符串"abacaba",里面包括4个'a',2个'b',1个'c',于是这个字符串的价值为4 * 4 + 2 * 2 + 1 * 1 = 21
牛牛有一个字符串s,并且允许你从s中移除最多k个字符,你的目标是让得到的字符串的价值最小。

输入描述:
输入包括两行,第一行一个字符串s,字符串s的长度length(1 ≤ length ≤ 50),其中只包含小写字母('a'-'z')。
第二行包含一个整数k(0 ≤ k ≤ length),即允许移除的字符个数。


输出描述:
输出一个整数,表示得到的最小价值
示例1

输入

aba
1

输出

2

思路

先计算每个字母出现次数,然后每次减出现次数最高的那个,注意:没减一次最大值会变化。

import java.util.Arrays;

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String inputString = scanner.nextLine();
        int k = scanner.nextInt();
        scanner.close();
        // 记录每个元素出现次数
        int[] numArray = new int[26];
        for (int i = 0; i < inputString.length(); i++) {
            numArray[inputString.charAt(i) - 'a']++;
        }
        // 按照出现次数进行排序
        Arrays.sort(numArray);

        for (int i = numArray.length - 1; i >= 1; i--) {
            // 该值必须大于后面的值,加上下面的排序保证每次都是减出现次数最多的那个位置值
            while (numArray[i] > 0 && numArray[i] >= numArray[i - 1] && k > 0) {
                numArray[i]--;
                k--;
                // 每次减完排序,一直减最大的那个
                Arrays.sort(numArray);
            }
        }

        long sum = 0;
        for (int i = 0; i < numArray.length; i++) {
            sum += numArray[i] * numArray[i];
        }

        System.out.println(sum);
    }
}
发表于 2020-06-23 14:49:30 回复(0)
如何才能保证价值最小,当然是将出现次数最多的字符变为出现次数不是最多的,如何不是最多?只要比第二多的小即可。循环,当将整数k消耗光的时候,求价值,此时最小。
#include<iostream>
#include<string>
#include<map>
#include<queue>
#include<utility>
#include<cmath>

using namespace std;

class Solution {
public:
	/**********************************字符串价值********************************************/
	void returnMinValue() {
		string str;
		cin >> str;
		map<string, int> dir;
		while (!str.empty()) {
			++dir[str.substr(0, 1)];
			str.erase(0, 1);
		}
		priority_queue<pair<int, string>> pque;
		for (auto begin = dir.begin(); begin != dir.end();++begin) 
			pque.push(make_pair((*begin).second, (*begin).first));
		int k = 0;
		cin >> k;
		int res = 0;
		while (!pque.empty()) {
			pair<int, string> curr = pque.top();
			pque.pop();
			int dif = curr.first - pque.top().first;
			if (dif >= k) {
				res += pow((curr.first - k), 2);
				while (!pque.empty()) {
					res += pow((pque.top().first), 2);
					pque.pop();
				}
				cout << res << endl;
				return;
			}
			else {
				curr.first -= (dif + 1);
				k -= (dif + 1);
				pque.push(curr);
			}
		}
		
	}
};

int main() {
    
	Solution s3;
	s3.returnMinValue();
	system("pause");
	return 0;
}


发表于 2020-06-19 22:16:29 回复(0)
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>

int main()
{
    std::string input("");
    std::cin >> input;
    int k = 0;
    std::cin >> k;
    int arr[26] = {0};
    for (int i = 0; i < input.length(); i++)
    {
        arr[input.at(i) - 'a'] += 1;
    }
    std::vector<int> sort_arr;
    for (int i = 0; i < 26; i++)
    {
        if (arr[i] > 0)
            sort_arr.push_back(arr[i]);
    }
    int t = 0;
    std::sort(sort_arr.begin(), sort_arr.end());
    int max_site = sort_arr.size() - 1;
    int second_site = max_site;
    while(k > 0)
    {
        /*
            最小的价值不是让最大的数减k,而是让各个数尽量小
            首先要让最大的数减到和第二大的数一样,然后再将第一和第二大的数减到和第三大的数一样
            如果所有数都一样,再依次减一
            直到K用尽
            */
        if (sort_arr[max_site] == sort_arr[second_site])
        {
            if (second_site >= 0)
            {
                int t = second_site;
                for (int i = second_site; i >= 0; i--)
                {
                    if (sort_arr[i] < sort_arr[second_site])
                    {
                        t = i;
                        break;
                    }
                }
                second_site = t < second_site ? t : -1;
            }
            
        }
        for (int i = sort_arr.size() - 1; i > second_site && k > 0; i--)
        {
            sort_arr[i] -= 1;
            k -= 1;
        }
    }
    
    int64_t value = 0;
    for (int i = 0; i < sort_arr.size(); i++)
    {
        value += (sort_arr[i] * sort_arr[i]);
    }
    std::cout << value << std::endl;
    return 0;
}

发表于 2022-04-08 18:07:36 回复(0)
s = str(input())
k = int(input())
d = {}
for c in set(s):
    d[c] = s.count(c)
nums = list(d.values())
minus = 0
while minus < k:
    nums.sort(reverse=True)
    nums[0]-=1
    minus+=1
print(sum([n**2 for n in nums]))

发表于 2021-07-21 21:06:50 回复(0)
import java.util.*;
public class Main{
  public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        int k = sc.nextInt();
        sc.close();
        int[] nums = new int[26];
        int res = str.length() - k;
        if (res < 2) {
            System.out.println(res);
            return;
        }

        for (int i = 0; i < str.length(); ++i) {
            nums[str.charAt(i) - 'a']++;
        }
      
        Arrays.sort(nums);
        int maxIndex = 25,i = 25;
        res = 0;
        while (k > 0) {
            if (maxIndex == 0) {
                nums[maxIndex] -= k;
                k = 0;
            }
            while (k> 0 && nums[maxIndex] > nums[maxIndex - 1])
            {
                for( i = maxIndex;k>0 &&i<26;++i){
                    --nums[i];
                    --k;
                }
            }
            --maxIndex;
        }
        for (int j = 0;j<=maxIndex;++j){
            res += (int)Math.pow(nums[j], 2);
        }
        if(maxIndex<25) {
            res += (i - maxIndex  - 1) * (int) Math.pow(nums[maxIndex + 1], 2);
            if(i<26)
                res += (26 - i) * (int) Math.pow(nums[i], 2);
        }
        System.out.println(res);
    }
}

发表于 2020-02-20 20:16:02 回复(0)
思路比较简单,就是先统计各个字符出现的次数,然后利用贪心算法结合最大堆每次移除出现次数最多的一个元素。
#include<iostream>
#include<string>
#include<map>
#include<utility>
#include<vector>
#include<iterator>
#include<cmath>       //幂指数的头文件
#include<algorithm>    //make_heap头文件
using std::string;using std::map;using std::pair;using std::make_pair;using std::vector;
using std::cin;using std::cout;using std::endl;using std::getline;using std::make_heap;

map<char,size_t> str_count(const string& str){             //计算string中各char出现的次数,以map形式表示
    string::const_iterator iter = str.begin();
    map<char,size_t> char_map;
    while(iter != str.end()){            //插入参考Primer385页
        auto ret = char_map.insert(make_pair(*iter,1));
        if(!ret.second)
            ++ret.first->second;
        ++iter;
    }
    return char_map;
}

vector<size_t> map_2_vec(map<char,size_t>&char_map){          //将上一函数出现的map转变为vector形式,即仅表示string中各字符出现的次数
    vector<size_t>vec_count;
    auto map_iter = char_map.cbegin();
    while(map_iter!=char_map.cend()){
        vec_count.push_back(map_iter->second);
        ++map_iter;
    }
    char_map.clear();           //删除原始的map,释放空间
    //char_map.erase(char_map.begin(), char_map.end());
    return vec_count;
}

int vec_sum(const vector<size_t>& vec_count){
    int count = 0;
    for(auto vec:vec_count){
        count += pow(vec,2);
    }
    return count;
}

int main(int argc,char* argv[]){
    string str;
    int change_num;
    getline(cin,str);cin>>change_num;           //读取命令行输入
    if(str.empty()||str.size()<=change_num){           //判断输入数据
        cout<<0<<endl;
        return 0;
    }
    map<char,size_t>char_map = str_count(str);            //统计string中字符出现的关联容器
    vector<size_t>vec_count = map_2_vec(char_map);
    while(change_num){                      //对vector构建最大堆,每次将最大的数值减一;
        make_heap(vec_count.begin(), vec_count.end(), std::less<size_t>());
        --vec_count[0];
        --change_num;
    }
    int count = vec_sum(vec_count);               //计算删除后的vec各元素的平方和。
    cout<<count<<endl;
    return 0;
}


发表于 2020-01-07 11:58:41 回复(0)
import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String str = bf.readLine();
        int num = Integer.parseInt(bf.readLine());
        int[] array = Delete(str,num);
        int count=0;
        for (int a:array){
            count+=a*a;
        }
        System.out.println(count);
    }
    static int[] Delete(String str,int num){
        int[] array = new int[26];
        for(int i=0;i<str.length();i++){
            array[(int)str.charAt(i)-'a']++;
        }
        for (int i=0;i<num;i++){
            Arrays.sort(array);
            array[array.length-1]--;
        }
        return array;
    }
}

发表于 2019-10-16 20:18:44 回复(0)
input_str=input()
remove_n=int(input())
input_list=[i for i in input_str.strip()]
k={}
for i in input_list:
    if i in k:
        k[i]+=1
    else:
        k[i]=1
list_n=[k[i] for i in k]
while remove_n:
    max_index=list_n.index(max(list_n))
    list_n[max_index]-=1
    remove_n-=1
s=0
for i in list_n:
    s+=i*i
print(s)

发表于 2019-08-26 21:25:36 回复(0)
var str=readline()
    var num=readline()
    var obj={}
  
    var arr=[]
    for(i=0;i<str.length;i++){
        if(!obj[str[i]]){
            obj[str[i]]=1
        }else{
            obj[str[i]]++
        }
    }

for(var key in obj ){
    arr.push(obj[key])
}
arr=arr.sort(function(a,b){
    return b-a
})
for(j=0;j<num;j++){
    arr[0]--
   arr= arr.sort(function(a,b){
    return b-a
})
}
var num=0
for(z=0;z<arr.length;z++){
    num=num+arr[z]*arr[z]
}
print(num)
发表于 2019-08-25 15:50:52 回复(0)
import java.util.*;
public class Main{
    public static void main(String []args){
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        int k = sc.nextInt();
        int[] array = new int[26];
        //array[0]代表a出现的次数,后面依次类推
        for(int i = 0; i < str.length(); i ++){
            char temp = str.charAt(i);
            int num = temp - 'a';
            array[num]++;
        }
        //每次array数组中最大的数减一,为了找到最大的数,通过Arrays.sort()进行排序
        int count = 0;
        while(k != count){
            Arrays.sort(array);
            if(array[array.length-1] != 0){
                array[array.length-1]--;
                count ++;
            }
        }
        
        int sum = 0;
        //数组的平方和就是最后的结果
        for(int j = 0; j < array.length; j ++){
            sum += Math.pow(array[j], 2);
        }
        System.out.println(sum);
        return;
    }
}


发表于 2019-08-19 11:27:38 回复(0)