计数质数
题目:统计所有小于非负整数 n 的质数的数量。
思路:不吹不黑,这道题我会做。依稀记得当年java入门就有一道100以内质数个数的题。这个题不过是把100换成了n而已。待我去写代码。
我回来了,再次打脸:这个和100以内质数不一样,因为按照老方法解会超时。我也很绝望啊~哎,果然偷懒不得,我先去优化再来。
优化完了,直接贴代码:
class Solution {
public int countPrimes(int n) {
if(n<=2){
return 0;
}
int i = 3;
//因为1,2直接不算,所以减2.这个范围的偶数肯定能被整除,所以除2.从奇数开始判断。最后+1是因为从3开始,3的时候 已经包含一个2了。
int result = (n-2)/2+1;
while(i<n){
for(int j=3;j*j<=i;j++){
//进来说明被除了1和它本身的数整出了,不是负数
if(i%j==0){
result--;
break;
}
}
//偶数绝对能被2整数,所以直接判断奇数
i=i+2;
}
return result;
}
}
上面优化了两个点,一个是偶数不判断,还有一个因数循环的时候i*i<=n。
做是做出来了,效率低的可怜,我去看看大神们的思路,大神思路也就这样,性能是测试案例的事,数据大了肯定算的麻烦,除非把比较大的几个测试案例都提出来。。说真的,这个提高性能的办法也是醉了,哈哈
同构字符串
题目:给定两个字符串 s 和 t,判断它们是否是同构的。如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
思路:这个其实就是字符串结构的比较。我也不知怎么说,一个是一个个比较,一个是放在map里比较。我一开始是做了暴力版本一个个跟之前元素比,其中一个相同就去判断另一个相同不相同。本地怎么测都ok,但是提交就超时,我把超时的案例放到本地跑就没问题,简直日狗了。我去琢磨优化了。
最终这个题还是用map做了。逻辑就是每一个s中的字符和t中的字符作为一对放在map中。然后遍历比较。map中没有往里存,map中有比较这次的s中字符t中字符和以前存放的对值是不是一样。不是证明不是同构。是继续往下。遍历完都没有不是的则说明是同构。
贴上代码:
public boolean isIsomorphic(String s, String t) {
Map<Character,Character> map = new HashMap();
for(int i=0;i<s.length();i++){
//如果key存在value却不存在说明出现问题了。只有keyvalue都不存在才往里添加
if(!map.containsKey(s.charAt(i))&&!map.containsValue(t.charAt(i))){
map.put(s.charAt(i),t.charAt(i));
}else{
//到这两种情况,一种是kv已经有了而且正确,还有一种是kv有其中一个但是成对不正确
if(map.get(s.charAt(i))==null || t.charAt(i)!=map.get(s.charAt(i))){
return false;
}
}
}
return true;
}
这道题这种解法很简单,但是性能堪忧,一开始我不想用这个就是因为map的.containsKey,.containsValue性能消耗大。我去看看有什么优化的思路没:
学到一招:换成char数组。判断第一次出现某字符的下标。一直都一样说明一样构造,有不一样的说明不同。这个性能比map好得多。只要看了代码很容易理解思路(对,就是看了人家这么写很容易理解,自己写不出来那种)
public boolean isIsomorphic(String s, String t) {
char[] ch1 = s.toCharArray();
char[] ch2 = t.toCharArray();
int len = s.length();
for (int i = 0; i < len; i++) {
if(s.indexOf(ch1[i]) != t.indexOf(ch2[i])){
return false;
}
}
return true;
}
反转链表
反转一个单链表。
思路:这个题似曾相识啊,我绝对是见过差不多类似的。而且上一次也是这个进阶要求,我递归很容易做出来了,迭代还是看了解析,用到了queue队列,当时还没太看明白。对,就是这么个故事。别不多谈,继续说这道题的思路:遍历输入的链表。新建一个链表,每次都往上挂节点就ok了。我去撸代码。
好了,写完回来了,思路没问题,实现起来也没难度,就是这个性能真让人脑仁痛,直接贴代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
//head是空直接返回,省的浪费时间,而且走到下面还得报空指针
if(head==null)
return null;
//预设的结果集,先把第一个节点挂上。
ListNode result = new ListNode(head.val);
//这里直接判断head.next。
while(head.next!=null){
//第一个节点已经挂上了。所以直接开始挂下一个
head = head.next;
//这个是作为新的根节点
ListNode cur = new ListNode(head.val);
//把之前的节点作为后面的节点挂上
cur.next = result;
//把最新的链表赋值给result。
result = cur;
}
return result;
}
}
讲真的,我还以为我条理挺清晰代码挺简单的呢,结果就这么个性能???
对了,还有递归的办法:
public ListNode reverseList(ListNode head) {
return reverse(null,head);
}
private static ListNode reverse(ListNode pre,ListNode cur){
if(cur==null) return pre;
ListNode next = cur.next;
cur.next = pre;
return reverse(cur,next);
}
今天就整理到这里,如果稍微帮到你了记得点个喜欢点个关注呦~也祝大家工作顺顺利利!