mituh's notes


  • 首页

  • 归档

Java中对String对象赋值

发表于 2018-08-07

在学习《算法》的时候, P42中提到
赋值语句不会创建新的对象, 而只是创建另一个指向某个已经存在的对象的引用
并且,
在Java中, 所有的非原始数据类型都是对象, 包括数组

Java中原始的数据类型有: byte,short,int,long,char,float,double和boolean。

这些基本类型可以分为四组:

整数 - 包括:byte,short,int和long,用于整数有符号数字。
浮点数 - 包括float和double,表示具有分数精度的数字。
字符 - 包括字符,表示字符集中的符号,如字母和数字。
布尔(Boolean) - 此组包括布尔值,它是表示 true/false 值的特殊类型。

回到刚才的问题上, 但在练习中出现了如下代码,

// PrintString_04.java

public class PrintString_04 {
public static void main(String[] args) {
// String string1 = new String("hello");
String string1 = "hello";
String string2 = string1; // string2是string1的引用?
string2 = "world"; // 修改string2, string1为何不发生改变?
StdOut.println(string1);
StdOut.println(string2);
}
}

/*
String string1 = "hello";
String string2 = string1; // string2确实是指向string1的引用
string2 = "world"; // 创建新的对象"wolrd", 此时string2指向新对象的引用
*/

Java中的String对象不可变, 对对象赋值是指向等号右边对象的引用, 但对String对象赋值时, 等号右边的双引号中的字符串, 实际上是新创建了一个对象, 指向了新对象的引用。

主要困惑我的地方,一开始没看清楚String和42页左下角Counter对象在赋值时候的区别。

Counter c1 = new Counter("ones");
c1.increment();
Counter c2 = c1;
c2.increment();
StdOut.println(c1);

那段代码的第三行,

Count c2 = c1;   // c1是不是创建新的对象的,c2指向的就是c1的地址

而

string2 = "world";  // 看似差不多, 实际上"world"是个新对象, string2指向新对象

目前, 因为String的不变性, 我暂时把String理解成和原始数据类型一样来操作, 就可以了.

ref:
https://blog.csdn.net/ilvest/article/details/64904520
https://blog.csdn.net/zhangjg_blog/article/details/18319521

配置jdk环境和classpath

发表于 2018-08-06

学《Algorithms》这本书的时候, 教材有一套自己的标准库

Getting started. To use this class, you must have StdIn.class in your Java classpath.
If you used our autoinstaller, you should be all set.
Otherwise, either download stdlib.jar and add to your Java classpath or download StdIn.java and put a copy in your working directory.

ref:https://introcs.cs.princeton.edu/java/stdlib/javadoc/StdIn.html

ls -l /usr/bin/java
lrwxr-xr-x 1 root wheel 74 Jun 17 16:18 /usr/bin/java -> /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java

这个只是替身路径, Go to这个路径, 展开后在
/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home找到真实路径

编辑~/.bash_profile中(我的是这个)

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home #jdk安装路径   
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/stdlib.jar

需要把从《Algorithms》上下载下来的stdlib.jar放入JAVA_HOME的lib文件中.

保存并

source .bash_profile

1033. 旧键盘打字(20)-PAT乙级

发表于 2018-08-04

1033 旧键盘打字(20)(20 point(s))

旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及坏掉的那些键,打出的结果文字会是怎样?

输入格式:

输入在2行中分别给出坏掉的那些键、以及应该输入的文字。
其中对应英文字母的坏键以大写给出;
每段文字是不超过10^5^个字符的串。
可用的字符包括字母[a-z, A-Z]、数字0-9、以及下划线“_”(代表空格)、“,”、“.”、“-”、“+”(代表上档键)。
题目保证第2行输入的文字串非空。

注意:如果上档键坏掉了,那么大写的英文字母无法被打出。

输出格式:

在一行中输出能够被打出的结果文字。如果没有一个字符能被打出,则输出空行。

输入样例:

7+IE.
7_This_is_a_test.

输出样例:

_hs_s_a_tst

Solution:

只有打出和打不出两种情况。
打不出分成: 数字字符对应, 英文字符 对应 坏键大写, ‘+’导致所有大写字符都打不出.
每次输入一个字符去和坏键对比, 打印出ok的字符

case2 error:

没有一个字符能被打出的情况
abcd
abcd

+
+

+
aabb22BSa2

排除不可用字母 这是我想到的一个边界情况, 不可用字符需要被当作无效输入跳过的
abc
a\bsd_\,

debug case2: 第一行 为空 的情况!! 怎么也没想到是第一行空, 也就是没有损坏键的情况

输入如下:

abcd
输出:
abcd

code:

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

// debug case 2: 可用字符就这么几个 -> 不是这个原因
int is_ok(char ch) {
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')
|| ('0' <= ch && ch <= '9')
|| (ch == ',' || ch == '.' || ch == '-' || ch == '+' || ch == '_'))
return 1;
return 0;
}

int main() {
string bad, input;
getline(cin, bad); cin >> input; // debug: 改用空行
// cin >> bad >> input; // case2: 通不过的原因, 第一行可能是空行
for (int i = 0; i < input.length(); i++) {
int ok = 1;
if (!is_ok(input[i])) continue;
for (int j = 0; j < bad.length(); j++) {
if (input[i] == bad[j]) {ok = 0; break;} // 直接对应相等
if (isalpha(input[i]) && (toupper(input[i]) == bad[j])) {
ok = 0; break; // 字符i是字母, 转成大写对应相等
}
if (bad[j] == '+' && isupper(input[i])) {
ok = 0; break; // 坏键是+, 对应i是大写
}
}
if (ok) cout << input[i];
}
cout << "\n";
return 0;
}

我学习了哈希散列之后, 在网上又看到这样的解法:

#include <iostream>
#include <string>
using namespace std;
int main() {
string bad, should;
getline(cin, bad);
getline(cin, should);
for (int i = 0; i < should.length(); i++) {
if (bad.find(toupper(should[i])) != string::npos) continue;
if (isupper(should[i]) && bad.find('+') != string::npos) continue;
cout << should[i];
}
return 0;
}

分析可得
1, 把操作都放在一个string中进行, 没有额外的vector, 减少了很多代码。

2, string对象, 可以调用find()函数, 如果找到了这个字符, 就返回这个字符的索引, 如果没找到, 返回一个与string::npos相等的值 cout << string::npos << endl; // 18446744073709551615

3, toupper和isupper的使用, 注意的是, toupper对非字母的字符也能起到作用, 因此可以将对整个字符串进行遍历

4, Hash散列, 通过查找HashTable中的key值, 判断key是否在列表中, 这里抽象出来, 就是判断某个字符ch, 或者是toupper(ch), 用find()函数判断是不是在这个字符串中, 在的给出相应的操作。

5, 这道题对不符合条件的进行忽略continue, 不符合的有两种:一种是转换成upper之后能在坏键字符串中找到的, 一种是, 另一种是大写, 但坏键中有”+”上档位键

1032. 挖掘机技术哪家强(20)-PAT乙级

发表于 2018-08-04

1032 挖掘机技术哪家强(20)

为了用事实说明挖掘机技术到底哪家强,PAT组织了一场挖掘机技能大赛。现请你根据比赛结果统计出技术最强的那个学校。

输入格式:

输入在第1行给出不超过10^5^的正整数N,即参赛人数。
随后N行,每行给出一位参赛者的信息和成绩,
包括其所代表的学校的编号(从1开始连续编号)、及其比赛成绩(百分制),中间以空格分隔。

输出格式:

在一行中给出总得分最高的学校的编号、及其总分,中间以空格分隔。题目保证答案唯一,没有并列。

输入样例:

6
3 65
2 80
1 100
2 70
3 40
3 0

输出样例:

2 150

Solution:

思路: 用数组存各个学校的总分, 计算完成之后, 得出总分最高的索引和总分

#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 100050;
int scores[MAXN];

int main() {
int N, max_i = -1, max_score = -1;
// memset(scores, 0, sizeof(scores)); // 这句造成编译错误
cin >> N;
for (int i = 0; i < N; i++) {
int j, tmp_s;
cin >> j >> tmp_s;
scores[j] += tmp_s;
if (scores[j] > max_score) { max_i = j; max_score = scores[j];}
}
cout << max_i << " " << max_score << "\n";
return 0;
}

1027. 打印沙漏(20)-PAT乙级

发表于 2018-08-02

1027 打印沙漏(20)

本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”,要求按下列格式打印

*****
***
*
***
*****

所谓“沙漏形状”,是指每行输出奇数个符号;各行符号中心对齐;相邻两行符号数差2;符号数先从大到小顺序递减到1,再从小到大顺序递增;首尾符号数相等。

给定任意N个符号,不一定能正好组成一个沙漏。要求打印出的沙漏能用掉尽可能多的符号。

输入格式:

输入在一行给出1个正整数N(<=1000)和一个符号,中间以空格分隔。

输出格式:

首先打印出由给定符号组成的最大的沙漏形状,最后在一行中输出剩下没用掉的符号数。

输入样例:

19 *

输出样例:

*****
***
*
***
*****
2

Solution:

S(a) = 1, 3, 5, 7, 9,
S(b) = 1, 7, 17 …
当n的值越过表b的某值时, 对应的星号的一种情况, 例如在[7, 17)都是不算1, 上下各两行.
因此只要计算前x项奇数*2+1的总和.

题中n<=1000,

(1+n) * (n/2)/2 = 500;
x = 31 (实际上我的x是调试出来的 :b)


// 计算前31项奇数之和

#include <stdio.h>

int main() {
int n; char ch;
scanf("%d %c", &n, &ch);
int i, j = 1, sum = 1, p;
for (i = 0; i < 31; i++) {
j += 2;
sum += j*2;
if (sum > n) {p = n - (sum-(j*2)); break;}
}
int line = i--;
// 上打印line行, 下打印line-1行
for (int i = line; i >= 0; i--) {
for (int j = 0; j < line-i; j++) printf(" ");
for (int j = 0; j < 1+i*2; j++) printf("%c", ch);
printf("\n");
}
for (int i = 1; i <= line; i++) {
for (int j = 0; j < line-i; j++) printf(" ");
for (int j = 0; j < 1+i*2; j++) printf("%c", ch);
printf("\n");
}
printf("%d\n", p);

return 0;
}

1026. 程序运行时间(20)-PAT乙级

发表于 2018-08-02

1026 程序运行时间(15)

要获得一个C语言程序的运行时间,常用的方法是调用头文件time.h,其中提供了clock()函数,可以捕捉从程序开始运行到clock()被调用时所耗费的时间。这个时间单位是clock tick,即“时钟打点”。
同时还有一个常数CLK_TCK,给出了机器时钟每秒所走的时钟打点数。
于是为了获得一个函数f的运行时间,我们只要

在调用f之前先调用clock(),获得一个时钟打点数C1;
在f执行完成后再调用clock(),获得另一个时钟打点数C2;
两次获得的时钟打点数之差(C2-C1)就是f运行所消耗的时钟打点数,
再除以常数CLK_TCK,就得到了以秒为单位的运行时间。

这里不妨简单假设常数CLK_TCK为100。现给定被测函数前后两次获得的时钟打点数,请你给出被测函数运行的时间。

输入格式:

输入在一行中顺序给出2个整数C1和C2。注意两次获得的时钟打点数肯定不相同,即C1 < C2,并且取值在[0, 10^7^]。

输出格式:

在一行中输出被测函数运行的时间。运行时间必须按照“hh:mm:ss”(即2位的“时:分:秒”)格式输出;不足1秒的时间四舍五入到秒。

输入样例:

123 4577973

输出样例:

12:42:59

Solution:

时分秒转换问题

根据打点数之差, CLK得到秒, 将秒转化为hh:mm:ss, 三次除以60(错误)
case 1通不过.

清晰的思路: 计算得到总共多少秒, hh:总秒数/3600取整, mm:剩余秒数/60取整, ss:剩余秒数四舍五入

这种看似简单的题目, 一旦出现没有预计到的问题, 容易东拼西凑的去完成.
因此刷题的时候还是先想清楚算法思路, 再开始动手, 更重要的是要注重数据结构, 别一味的铺张代码

#include <stdio.h>
#include <math.h>
#include <iostream>
using namespace std;

int main() {
double c1, c2;
scanf("%lf %lf", &c1, &c2);
double c = (c2-c1) / 100;

int h, m, s;
h = c/3600;
c = c-h*3600;
m = c/60;
c = c-m*60;
s = floor(c+0.5);
printf("%02d:%02d:%02d\n", h, m, s);
return 0;
}

也贴一下, 之前错误的版本。


int tm[3];
const int CT = 100;

int main() {
double c1, c2;
scanf("%lf %lf", &c1, &c2);
double s = (c2 - c1) / CT;
cout << s << endl;
int hh, mm, ss;
hh = s/3600;
mm = (s/3600-hh)*3600/60;
ss = floor(((s/3600-hh)*3600/60 - mm) * 60 + 0.5);
printf("%02d:%02d:%02d\n", hh, mm, ss);
return 0;
}

1024. 科学计数法(20)-PAT乙级

发表于 2018-08-02

1024 科学计数法 (20)(20 point(s))

科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式[+-][1-9]”.”[0-9]+E[+-][0-9]+,即数字的整数部分只有1位,小数部分至少有1位,该数字及其指数部分的正负号即使对正数也必定明确给出。

现以科学计数法的格式给出实数A,请编写程序按普通数字表示法输出A,并保证所有有效位都被保留。

输入格式:

每个输入包含1个测试用例,即一个以科学计数法表示的实数A。该数字的存储长度不超过9999字节,且其指数的绝对值不超过9999。

输出格式:

对每个测试用例,在一行中按普通数字表示法输出A,并保证所有有效位都被保留,包括末尾的0。

输入样例1:

+1.23400E-03

输出样例1:

0.00123400

输入样例2:

-1.2E+10

输出样例2:

-12000000000

Solution:

(可最后用前面计算出的数值, 配合小数点拼出了一个string, 这种做法十分不满意, 需要重新做一遍)
第一个正负号作为输出时, +不输出, -输出负作为开头,
把符号和E中间的数组放入字符串
E后符号-, 小数点向左移动位置, 整数部分数字个数 in
符号+, 小数点向右移动位置, 小数部分数字个数 fn

符号后字符串转化成整数, syb_n,

第二个[+-]决定, back/front, fn/in, 小数点左移/右移

flag == 0:
-1.23E+03 fn=2, syb_n=3, 末尾添1个0
-1.230
-1.2E+10 fn=1, syb_n=10, back=syb_n-fn=9 push_back 9个0, .右移syb_n

-1.234E+03 fn=3, syb_n=3,末尾添入0个0 syb_n-fn>0添syb-n个0
-1.234

flag == 1;
+17.56E-01 in=2, syb_n=1, 1-2+1=0 不添0, 小数点左移1位 添入几个0 syb_n-in+1 <= 0 不添
+17.56E-02 in=2, syb_n=2, 2-2+1=0, 添1个0 小数点左移2位 front=sys_n-in+1, .左移syb_n

*/

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

int main() {
char c;
c = getchar();
if (c == '-') cout << "-";
string s; // 数组和小数点部分
int in = 0, fn = 0, ok = 0; // 科学计数法的整数和小数部分个数, 转换标示
while ((c = getchar()) && c != 'E') {
if (c == '.') {ok = 1; continue;}
s.push_back(c);
ok ? fn++ : in++;
}
// 读第二个正负号
c = getchar();
int flag = (c == '+') ? 0 : 1;
// 读syb_n字符
vector<int> syb_v;
while ((c = getchar()) && (c != '\n') && (c != '\r')) {
syb_v.push_back(c - '0');
}
// 计算syb_n
int syb_n = 0, k = 1;
for (int i = syb_v.size() - 1; i >= 0; i--) {
syb_n += k * syb_v[i];
k *= 10;
}

int front = syb_n-in+1, back = syb_n-fn;
if (flag == 1) {
if (front > 0) cout << "0.";
for (int i = 0; i < front-1; i++) cout << "0";
cout << s;
}
if (flag == 0) {
if (back < 0) {
int len = s.size();
for (int i = 0; i < len; i++) {
if (i == len+back) cout << ".";
cout << s[i];
}
} else {
cout << s;
for (int i = 0; i < back; i++) cout << "0";
}
}
cout << "\n";
return 0;
}

1020. 月饼 (25)-PAT乙级

发表于 2018-08-02

1020 月饼 (25)

月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼。现给定所有种类月饼的库存量、总售价、以及市场的最大需求量,请你计算可以获得的最大收益是多少。

注意:销售时允许取出一部分库存。样例给出的情形是这样的:假如我们有3种月饼,其库存量分别为18、15、10万吨,总售价分别为75、72、45亿元。如果市场的最大需求量只有20万吨,那么我们最大收益策略应该是卖出全部15万吨第2种月饼、以及5万吨第3种月饼,获得 72 + 45/2 = 94.5(亿元)。

输入格式:

每个输入包含1个测试用例。每个测试用例先给出一个不超过1000的正整数N表示月饼的种类数、以及不超过500(以万吨为单位)的正整数D表示市场最大需求量。随后一行给出N个正数表示每种月饼的库存量(以万吨为单位);最后一行给出N个正数表示每种月饼的总售价(以亿元为单位)。数字间以空格分隔。

输出格式:

对每组测试用例,在一行中输出最大收益,以亿元为单位并精确到小数点后2位。

输入样例:

3 20
18 15 10
75 72 45
输出样例:

94.50

Solution:

计算各种月饼每吨的售价, 优先每吨售价最高的月饼填满需求, 剩下的用售价次高的填满
采用优先队列, dq放每个月饼结点, 价格越高结点会被排在更前面

注意一下测试点3(case 3)通不过的情况, 如果都供应完了, 还没达到市场需求的情况, 按当前供应量来计算价格

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;

struct Cake {
double num, tot;
double each_d;
};

struct cmp {
bool operator () (const Cake c1, const Cake c2) const {
return c1.each_d <= c2.each_d; // 每吨的价格越高权重越高
}
};
vector<Cake> cakes;
priority_queue<Cake, vector<Cake>, cmp > dq;


int main() {
int N, D; // 种类数和市场需求
cin >> N >> D;
for (int i = 0; i < N; i++) {
Cake tmp_c;
cin >> tmp_c.num;
cakes.push_back(tmp_c);
}
for (int i = 0; i < N; i++) {
cin >> cakes[i].tot;
cakes[i].each_d = cakes[i].tot / cakes[i].num;
dq.push(cakes[i]);
}
double ans = 0;
int now_d = 0;
for (;;) {
// debug case3: 如果都供应完了, 还没达到市场需求的情况
if (dq.empty()) break;
Cake cmax = dq.top();
if (D - now_d >= cmax.num) { // 如果需求量比当前最有优价格的供货量大
now_d += cmax.num;
ans += cmax.each_d * cmax.num;
} else { // 只需要提供一部分
ans += (D - now_d) * cmax.each_d;
now_d = D; // 供应部分后, 满足市场需求
break;
}
dq.pop(); // 队首月饼供应完毕
}
printf("%.2lf\n", ans);
return 0;
}

Solution2:

第二遍做, 优先队列的逻辑更直观, 注意正数和正整数的区别, 要将cnt声明成double, 不然case2过不了

#include <cstdio>
#include <queue>
#include <vector>
using namespace std;

struct food {
double scale, each_scale;
double cnt;
};

struct cmp {
bool operator() (const food &f1, const food &f2) {
return f1.each_scale < f2.each_scale;
}
};

bool db_equal(const double d1, const double d2) {
return -0.0005 < d1-d2 && d1-d2 < 0.00005;
}

int main() {
int N;
double need; scanf("%d %lf", &N, &need);
vector<food> v(N);
priority_queue<food, vector<food>, cmp> q;
for (int i = 0; i < N; i++) {
scanf("%lf", &v[i].cnt);
}
for (int i = 0; i < N; i++) {
scanf("%lf", &v[i].scale);
v[i].each_scale = v[i].scale / v[i].cnt;
q.push(v[i]);
}
double profit = 0.0;
while (!db_equal(need, 0.0) && !q.empty()) {
if (q.top().cnt > need) {
profit += q.top().each_scale * need;
need = 0;
} else { // <= need
profit += q.top().scale;
need -= q.top().cnt;
q.pop();
}
if (q.empty()) break;
}
printf("%.2lf", profit);
return 0;
}

1019. 数字黑洞(20)-PAT乙级

发表于 2018-08-02

1019 数字黑洞 (20)

给定任一个各位数字不完全相同的4位正整数,如果我们先把4个数字按非递增排序,再按非递减排序,然后用第1个数字减第2个数字,将得到一个新的数字。一直重复这样做,我们很快会停在有“数字黑洞”之称的6174,这个神奇的数字也叫Kaprekar常数。

例如,我们从6767开始,将得到

7766 - 6677 = 1089\ 9810 - 0189 = 9621\ 9621 - 1269 = 8352\ 8532 - 2358 = 6174\ 7641 - 1467 = 6174\ … …

现给定任意4位正整数,请编写程序演示到达黑洞的过程。

输入格式:

输入给出一个(0, 10000)区间内的正整数N。

输出格式:

如果N的4位数字全相等,则在一行内输出“N - N = 0000”;否则将计算的每一步在一行内输出,直到6174作为差出现,输出格式见样例。注意每个数字按4位数格式输出。

输入样例1:

6767

输出样例1:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174

输入样例2:

2222

输出样例2:

2222 - 2222 = 0000

Solution

思路:
模拟, 需要递减sort, 再递增排序
字符串转整数用于计算, 整数转字符串用于判断和表示
后来才记起来c++有 std::stoi/stol/stoll函数..
以及c++11新出的std::to_string()函数;

最近刷题总是拿捏不好什么时候用c, 什么时候用c++, 这个问题还需要做题和看更多代码来得出一些心得。

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

bool cmp_str1(const char a, const char b) { return a >= b;}

bool cmp_str2(const char a, const char b) { return a <= b;}


int convert_int(string s) {
// 从(末尾*10+前一位)*10
int i = 1, ans = 0;
for (string::iterator p = s.end()-1; p >= s.begin(); p--) {
ans += (*p - '0') * i;
i *= 10;
}
// cout << ans << "\n";
return ans;
}

string convert_str(int h) {
// 转成4位字符串,
string ans_s(4, '0');
int i = 3;
while (h) {
ans_s[i--] = h % 10 + '0';
h /= 10;
}
return ans_s;
}

int main() {
string s1;
cin >> s1;
s1 = convert_str(convert_int(s1)); // debug: 0~999需要处理
string s2 = s1;
sort(s1.begin(), s1.end(), cmp_str1);
sort(s2.begin(), s2.end(), cmp_str2);
if (s1 == s2) {
cout << s1 << " - " << s1 << " = 0000" << "\n"; return 0;
}
while (s1 != "6174") {
s2 = s1;
sort(s1.begin(), s1.end(), cmp_str1);
sort(s2.begin(), s2.end(), cmp_str2);
int d = convert_int(s1) - convert_int(s2);
string tmp = convert_str(d); // debug:按照四位格式输出
cout << s1 << " - " << s2 << " = " << tmp << "\n";
s1 = tmp;
}

return 0;
}

1017. A除以B(20)-PAT乙级

发表于 2018-07-31

1017. A除以B (20)

本题要求计算A/B,其中A是不超过1000位的正整数,B是1位正整数。你需要输出商数Q和余数R,
使得A = B * Q + R成立。

输入格式:

输入在1行中依次给出A和B,中间以1空格分隔。

输出格式:

在1行中依次输出Q和R,中间以1空格分隔。

输入样例:

123456789050987654321 7

输出样例:

17636684150141093474 3

Solution:

思路:
1, 用数组储存大整数, 模拟大整数除以1位数
2, 更省空间和减少循环次数的做法: 用C++字符串读取, 模拟手动除法, 首位整数 / B, 如果得到不是0就输出, 余数*10+下一位;


2优点在于,
边计算边输出;
首个索引与循环分开计算, 减少在循环内的判断;
对边界条件的定义处理在一个if语句中;
用string可以减少指针带来的诸多问题

#include <cstdio>
#include <cstring>
using namespace std;

char bs[1050];
int ans[1050];
int cnt = 0;

int main() {
int b, q = 0, r = 0;
scanf("%s %d", bs, &b);
int len = strlen(bs);
for (int i = 0; i < len; i++) {
int x = r * 10 + bs[i] - '0';
q = x / b;
r = x % b;
if (i == 0 && q == 0) continue;
ans[cnt++] = q;
}
if (cnt == 0 && ans[0] == 0) printf("0");
for (int i = 0; i < cnt; i++) { printf("%d", ans[i]); }
printf(" %d\n", r);
return 0;
}

修改后的代码:

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


int main() {
string a; int b;
cin >> a >> b;
int len = a.length();
int f = (a[0] - '0') / b;
if ((f != 0 && len > 1)|| len == 1)
cout << f;
int temp = (a[0] - '0') % b;
for (int i = 1; i < len; i++) {
f = (temp * 10 + a[i] - '0') / b;
cout << f;
temp = (temp * 10 + a[i] - '0') % b;
}
cout << " " << temp << "\n";
return 0;
}
1…121314…18

mituh

179 日志
99 标签
© 2018 mituh
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4