请独立完成本次作业后再看本推文

更有利于您的Matlab体验

这次的matlab作业相对于上一周的难度有了很大的提升,个人觉得十分的有意思,尤其q3可以找出很多种办法。无奈题目有很多限制,这给本次作业又增加了不少难度。

Requirements : Without if statement, without the operators && ||, without loops, without recursion, without str2num, without num2str, without 2d array.

听Israel听原理逻辑思路,听Tzvi听思路和实践,感觉都能收获很多,只是方向不同。记录一下自己的思考逻辑,或许以后会有很大启发。希望本文能提起大家对matlab的兴趣,找到非唯一解。

这道题对我来说,属于还可以接受的范围,花点时间,还是可以自己想出来的,我最初的答案如下

%get input from user

st=input('Please enter a string : ','s');

%判断st里每个元素是否在‘A’和‘a’之间,这些为大写字母

i=(st>='A')+(st<='a')==2;

%将大写字母转化为小写字母。对string(字符串)进行运算会自动转化为两个character的ASCII Value差,所以还要用char转回string

st=char(st+i*('a'-'A'));

b=st(end:-1,1);

%给a,b最后分别加上不同的string

a(length(st)+1)='1';

b(length(st)+1)='2';

%比较a,b里每个对应元素是否相同,输出逻辑数列c

%找到第一个不同元素的位数,减去一,即得到相同元素最后一位

r=min(find(c==0))-1;

%display the required result

i=(st>='A')+(st<='a')==2;

st=char(st+i*('a'-'A'));

其实可以简化为

st=lower(st);

这个函数可以将string中所有大写字母转化为小写字母;相应的,upper可以将string中所有小写字母转化为大写字母

先来说说我为啥要给a,b结尾分别加上一个不同的string。因为当st是一个回文序列时(从头读到尾和从尾读到头一样),a和b就是两个完全相同的string,c就不包含0。这样会导致find函数找不到0,从而丢出[]。[]做任何运算得到的结果都是[],那我们就会在回文序列情况下失败了。所以给a,b末尾加上两个不同的string,目的就是给c的结尾创造0,保证find不会返回[]。

后来Tzvi老师告诉我,其实不用这么麻烦,你不就要加个0吗?直接写为下面内容就好了

c=[a==b 0];

另外,matlab会不推荐你写min(find)这样的逻辑结构,Tzvi跟我解释说。写min的话,matlab要比较array里的所有元素,这样会导致运算减慢。更好的方法是直接取find到的第一个数,这样它就可以不用比较所有元素,而只是单单找到第一个就好了。

r=find(c==0,1)-1;

最后一点,strcmp是比较两个string是否完全相同(区分大小写);而strcmpi也是比较两个string是否完全相同,但是不区分大小写。

这样一来,我们第一题就可以得到我目前找到的最简方法

st=input('Please enter a string : ','s');

st=lower(st);

b=st(end:-1,1);

c=[a==b 0];

r=find(c==0,1)-1;

这道题开始就有点难度了,因为要求不能使用str2num等,就有点麻烦。不过好在,在Matlab Lab课上,有同学上去问他。我看了一下板书,就摸索出来了。

st=input('Please enter a string : ','s');

%首先找出运算符号的位置

id_logical=(st>='0')+(st<='9')==2;

a=find(id_logical==0);

%运算符号前后的数字分别叫b,c

b=sum((st(1:a-1)-'0').*10.^(length(st(1:a-1))-1:-1:0));

c=sum((st(a+1:end)-'0').*10.^(length(st(a+1:end))-1:-1:0));

%判断为何种运算符号,用logical替代if

plus=st(a)=='+';

minus=st(a)=='-';

multiply=st(a)=='*';

r=plus*(b+c)+minus*(b-c)+multiply*(b*c);

这里面的b运算,分成几部分来看可能比较好理解。

首先是st中1:a-1为b数字在st里的位数,st(1:a-1)-'0'就可以获得表示b的每一位数字的1*length(b)的array。让他们分别乘上对应位数(比如个位*10^0,十位*10^1,百位*10^2......),这就是后面的.*10.^(length(st(1:a-1))-1:-1:0)了。最后把这些数字sum起来就得到b。c也是同样的道理。

这道题就跟我开头说的一样,非常的有意思。

最先是我自己做的非常复杂的方法。

%---method 1---

st=input('Please enter a string : ','s');

%从st中提取数字1-9

p=st((st>='1')+(st<='9')==2)-'0';

%计算每个元素出现的次数,赋值于a

a(1)=sum(p==1);

a(2)=sum(p==2);

a(3)=sum(p==3);

a(4)=sum(p==4);

a(5)=sum(p==5);

a(6)=sum(p==6);

a(7)=sum(p==7);

a(8)=sum(p==8);

a(9)=sum(p==9);

%比较该元素出现次数是否等于其本身大小,赋值为b

b(1)=a(1)==1;

b(2)=a(2)==2;

b(3)=a(3)==3;

b(4)=a(4)==4;

b(5)=a(5)==5;

b(6)=a(6)==6;

b(7)=a(7)==7;

b(8)=a(8)==8;

b(9)=a(9)==9;

%b是否包含至少一个有非零数

%让不符合条件的数变为0

%让不符合的数从0变为10,防止等会min输出0

d(d==0)=10;

%若没有符合条件的数则输出0(c赋予这个能力),否则输出最小的数

r=c*min(d);

找相同元素的个数,除了可以用a=sum(p==num)之外,还可以写为a=length(find(p==num))

Tzvi告诉我不要这么复杂,万一要你找的数字很多怎么办,那你岂不是要写几十几百行?他提示我先把所有1-9的数提取出来,sort一下,通过array的方式想想。

但是,我想不出来......

所以我就去找大佬,日姐,她告诉了我很妙的方法

%---method 2---

st=input('Please enter a string : ','s');

a=st(find(((st>='0')+(st<='9'))==2));

c=[1 sum(b==1)==1 sum(b==2)==2 sum(b==3)==3 sum(b==4)==4 sum(b==5)==5 sum(b==6)==6 sum(b==7)==7 sum(b==8)==8 sum(b==9)==9];

e=d(find(c==1));

f=min(e(e>0));

r=max([f 0]);

这个方法很赞!有array的思维!

最最最让我赞叹的,她通过e这一行,一下子完成了判断,赋值两个步骤。把c==1在d里对应的元素赋值给e。

而且我这才意识到可以直接写e(e>0)来直接排除0,而不用对0进行修改,效率大大提高。

最后通过r行的max达到没有符合条件的数则输出0,否则输出f。有种any的思想,但感觉却更妙。

但是当我们输入a行时,会发现find被刷黄了。这实际上无伤大雅,是logical和array的区别而已。

find会输出符合条件元素在数列中的位置;而单纯只写判断的话,会输出只包含0,1的logical,1对应符合条件,0则相反。

当这两种输出项被变量用括号包起来的时候,输出的结果其实是一样的。

st=[1 2 3 4 5 6 7 9 8 9];

a=find(((st>=4)+(st<=6))==2)

b=((st>=4)+(st<=6))==2

日姐的方法固然很赞,但matlab是永不止步的。比如说,日姐的方法里的元素如果能够不用一个个输入就好了。否则万一题目要求的元素变多了怎么办?

我其实还有一个方法。这个方法是一个2-dimension array的例子,不符合限制,但它比较有趣,所以我也写下来了。

%---method 3---

st=input('Please enter a string : ','s');

%它提取了st里的1-9元素,并对其进行由小到大的排序,得到1xlength(a)的矩阵

a=sort(st((st>='1')+(st<='9')==2)-'0');

%建立一个1:9的矩阵,并转置,使其变成一个9x1的矩阵

b=transpose(1:9);

%将a,b里的元素一一判断是否相同,得出一个length(b)xlength(a)的矩阵

d=[1 transpose(sum(c,2))==(1:9)];

g=min(f(f>0));

r=max([g 0]);

transpose就是让矩阵转置的函数。

这里我觉得得着重解释一下c行,就像上面说的一样,a是1xlength(a)的矩阵,b是9x1的矩阵。这样一来,c的第一行就是a里的每一个元素与b的第一个元素进行比较,即a第一行与b第一行进行比较。以此类推,c的第二行是a的第二行与b的第二行进行比较......

在本题中,c的第一行就会得到'1'在a里的logical数组,后面其他数字亦是如此。

a=[1 1 2 3 2];

d行中的,sum(c,2)指的是把c每一行的所有元素加起来。不写2,或者写成1的话,就是每一列加起来。之后其他部分都与日姐的方法相似,就不再说明了。

之后我在看到了不少奇妙的方法,接下来我只介绍两种我看得懂的方法

%---method 4---

st=input('Please enter a string : ','s');

a=st((st>='1')+(st<='9')==2)-'0';

b=tabulate(a);

c=[1 b(1:9,2)];

f=min(e(e>0));

r=max([f 0]);

我们只要看中间就好了,开头和结尾刚刚都已经介绍过了,提取1-9的元素;通过判断赋值,有符合条件的输出最小值,否则输出0。

这里用到了tabulate,它会把数列里的所有元素排列,并列出各个元素的个数以及所占百分比。b被赋值为,第一列为元素,第二列为元素的个数,第三列为元素站总数的百分比。

b=tabulate(a)

%---method 5---

st=input('Please enter a string : ','s');

a=st((st>='1')+(st<='9')==2)-'0';

b=hist(a,unique(a));

r=e*min(f(f>0));

我觉得这个例子太牛掰了,它用了直方图,不是2-dimension array,符合题目限制,个人感觉是最优解。但老师没教过,所以八成不是老师想要的答案。

hist就是直方图的意思,但这个函数在更新后便不再推荐了,一般替代为histogram。但我们这个例子就是需要hist

hist的格式为hist(data,bins)

unique就是取出所有不同的元素并且sort

所以他这里写b=hist(a,unique(a))就相当于找出了每个元素的个数,而且题目要求1-9每个数字都有,所以bins不会少任意个数而导致无法和c进行比较。后面与我第一个方法一样,就不再说明了。

答案:略

st = input('Please enter a string : ','s');

%分别找出'_'和字母的位置,进行差位比较,找出‘_’和字母交界时字母的位数

a=st(1:end-1)=='_';

b=st(2:end)~='_';

c=find(a+b==2)+1;

%因为第一个字母串首字母不用大写,删去

%从第二个字母串开始首字母大写

st(c)=upper(st(c));

%删去‘_’

r=st(st~='_');

这个题目很坑,不能用2-dimension array,不然还挺简单。这个问题我想了很多天,至今未找到最优解。

先讲讲我自己最先的方法吧。

a = input('Please enter a 1 line array of integers : ');

k = input('Please enter k (k>=1) : ');

c = 1:length(a);

r((c-1).*k+1:c.*k)=a(c);

我尝试着解释一下我的想法。

我们要扩张我们的array,使得我们array里每个元素重复k遍后再到下一个元素。

c是一个1:length(a)的array。

r行的运作原理如下:

假设k=3,a=[1 2 3]

从c的第一个元素c(1)=1开始,r((1-1)*3+1:1*3)=r(1:3)=a(1)

把r的第1到3个元素赋值为a(1)

然后,c的第二个元素c(2)=2开始,r((2-1)*3+1:2*3)=r(4:6)=a(1)

把r的第4到6个元素赋值为a(2)

一直到c(end)都是如此。

这个设想很美好,但可惜是error,因为r行等号两边元素个数不同,赋值失败。

然后试试2-dimension array的方法,repmat

a = input('Please enter a 1 line array of integers : ');

k = input('Please enter k (k>=1) : ');

b = sort(repmat(1:length(a),1,k)

repmat就是replicate matrix,比如repmat(a,b,c),就是将a竖着重复b次,横着重复c次

d=repmat(a,b,c)

我们sort了repmat,让相同的位数出现在同样的地方

b=repmat(1:length(a),1,4)

我后来了解到一个很神奇的函数,叫repelem(replicate element),我觉得它可以达成非2

-dimension array的条件。

a = input('Please enter a 1 line array of integers : ');

k = input('Please enter k (k>=1) : ');

r = repelem(a,k);

当k如题目中所讲一样,只是一个数字而已,那它就可以每个元素重复k遍后再到下一个元素。

r=repelem(a,k)

而且当k为数字时,a只能为1xn或者nx1的vector(1-dimension array),否则会error

当k不为数字的时候,repelem还可以这么写

r=repelem(a,k)

当然了,repelem还有其他许许多多的玩法,大家可以自行浏览document。

以上就是我对matlab本次作业的逻辑思考,肯定有很多的不足,大家都可以指出来,有更好的方法也提出来,相互学习学习,谢谢啦!