剑指offer-第5章优化时间和空间效率(丑数)

题目:我们把只包含因子2,3,5的数叫做丑数。寻找第1500个丑数。通常把1当成第一个丑数。

思路1:第一步判断是否为丑数:丑数是只包含2,3,5的数,因此一定可以被2,3,5整除。通过求余数是否为零做为判断条件,通过除以来减小整个数的值,知道整个数为1.返回true.

第二步找到第N个丑数的值,这一种做法的缺点是,不是丑数的数也要求余数除数的运算,因此耗时。因此我们提出一种以空间换时间的方法(谁让如今硬件更新的快呢)。如2思路。

思路2:我采用一个数组按照从小到大的顺序存放丑数。数组中最后一个放入的丑数即是最大的丑数M。然后,将M之前的数分别乘以,2,3,5来找到下一个大于M的丑数。改变M的值为最后找的的丑数。在2乘以M之前的丑数的时候一定存在某个丑数在它之前的数和2相乘都小于M,之后的数都大于M。我们可以记录下这个数。并且更新它。就可以很快的找到和2相乘大于M的那个丑数了。

Java代码思路1:

//思路:第一步:判断一个数是否为丑数。由于丑数是只包好2,3,5的因子的数,因此我们自然就想到了判断一个丑数先对2进行求余数如果为0再对它进行求除数减小数的大小,
//同样对3,和5也一样,最后如果结果为1就返回true。第二步,通过判断是否为丑数来数出第N个丑数对应的值。
public class FindUglyNumber {
    //判断一个数是不是丑数
    public boolean isUgly(int number){
        if(number<=0)
            return false;
        while(number%2==0)
            number/=2;
        while(number%3==0)
            number/=3;
        while(number%5==0)
            number/=5;
        return (number==1)?true:false;
    }
    public int uglyNumber(int uglyNumber){
        if(uglyNumber<=0)
            return 0;
        int ugly=0;//记录丑数的个数
        int number=0;//记录数字
        while(ugly<uglyNumber){
            number++;
            if(isUgly(number))
                ugly++;
        }
        return number;
    }
    public static void main(String[] args){
        FindUglyNumber findUglyNumber=new FindUglyNumber();
        int uglyNumber=findUglyNumber.uglyNumber(3);
        System.out.println(uglyNumber);
    }

}

Java代码思路2:

//思路:将uglyNumber按照从小到大的顺序保存在数组中。因为uglyNumber是只包含2,3,5因子的数,
//因此可以用一个M表示数组中最大的数,也是数组中最后一个存入的数,而将之前的丑数分别乘2,3,5,然后保留大于M值的最小数。
//作为下一个M。我们前面说,M之前的每一个丑数都乘以2,3,5,其实这个可以确定在乘以2时在一定存在某个值,在它之前的数都小于M
//在它之后的数都大于M。
public class FindUglyNumber1 {
   public int findUglyNumer(int index){
       int[] uglyNumber=new int[index];
       uglyNumber[0]=1;
       int nextNumber=1;
       int nextNumber2=0;
       int nextNumber3=0;
       int nextNumber5=0;
       while(nextNumber<index){
           int min=min(uglyNumber[nextNumber2]*2,uglyNumber[nextNumber3]*3,uglyNumber[nextNumber5]*5);
           uglyNumber[nextNumber]=min;
           while(uglyNumber[nextNumber2]*2<=uglyNumber[nextNumber])
               nextNumber2++;
           while(uglyNumber[nextNumber3]*3<=uglyNumber[nextNumber])
               nextNumber3++;
           while(uglyNumber[nextNumber5]*5<=uglyNumber[nextNumber])
               nextNumber5++;
           nextNumber++;
       }
       int ugly=uglyNumber[nextNumber-1];
       return ugly;
   }

public int min(int i, int j, int k) {
    int min=i<j?i:j;
    return min<k?min:k;
}
public static void main(String[] args){
    FindUglyNumber1 findUglyNumber=new FindUglyNumber1();
    int uglyNumber=findUglyNumber.findUglyNumer(3);
    System.out.println(uglyNumber);
}

}
时间: 2024-10-26 05:26:04

剑指offer-第5章优化时间和空间效率(丑数)的相关文章

剑指Offer面试题34(java版):丑数

题目:丑数 * 我们把只包含因子2,3,5的数称为丑数(Ugly Number). * 求按从小到大的顺序的第1500个丑数. * 例如6,8都是丑数,但14不是,因为它含有因子7.习惯上我们把1当作第一个丑数 方法一:逐个判断每个整数是不是丑数的解法,直观但不够高效: 所谓一个数m是另一个数n的因子,是指n能被m整除,也就是说n%m==0.根据丑数的定义,丑数只能被2,3,5整除.也就是说如果一个数能被2整除,我们把它连续除以2:如果能被3整除,就连续除以3:如果能被5整除,就除以5.如果最后

剑指offer-第五章优化时间和空间效率(从1到n的整数中1出现的次数)

题目:输入一个整数n,从1到n这n个十进制整数中1出现的次数. 思路1:对1到n中的任意一个数i对其进行求余数来判断个位是否为1,然后再求除数,判断十位是否为1.统计出1的个数.然后对1到n用一个循环将所有的数都加起来.时间复杂度为O(nlogn). 思路2:根据数字的规律来求.例如:21344这个数,我们将它分成两部分,第一部分为1345~21344.这部分我们可以先求出最高位上一出现的次数.又分为两种情况,10000~19999这种情况下最高位大于1,1出现的次数为10^4,另一种是1000

剑指offer-第五章优化时间和空间效率(数组中的逆序对的总数)

题目:在数组中如果两个数字的前面的数比后面的数大,则称为一对逆序对.输入一个数组求出数组中逆序对的总数. 以空间换时间:思路:借助一个辅助数组,将原来的数组复制到该数组中.然后将该数组分成子数组,然后统计子数组中内部的逆序,然后再统计两个相连的子数组中的逆序对,这个过程用到了归并排序.时间复杂度为O(nlogn). 如下图所示:

剑指offer-第五章优化时间和空间效率(在字符串中第一次出现切只出现一次的字符)

题目:在字符串中第一次出现切只出现一次的字符 思路:用HashMap来存放对应的char值和该char出现的次数.做一次变量就可以得到第一个只出现一次的字符. Java代码: import java.util.LinkedHashMap; //思路:用HashMap来存放对应的char值和该char出现的次数.做一次变量就可以得到第一个只出现一次的字符. public class FirstNotRepeatingChar { public Character firstNotRepeating

剑指offer-第五章优化时间和空间效率(两个链表的第一个公共节点)

思路1:要求的是两个链表的第一个公共节点,首先想到的是用栈来存放两个链表,然后依次从栈中抛出,直到最后一个相同的节点为止.但是要用到两个栈,空间复杂度为O(n): 思路2:从头到尾分别遍历两个链表得到链表的长度风别为,len1和len2,求出两者的差值dif,然后现在长的链表上面走dif步,然后同步走剩下的节点,当就可以找到第一个公共节点了. public ListNode findFirstCommonNode(ListNode pHead1,ListNode pHead2){ if(pHea

剑指offer第4章

包含 \(min\) 函数的栈 ? 利用辅助栈,把每次的最小者(之前的最小元素和新压入栈的元素的两者中的较小值)都保存起来放到另一个辅助栈中. ? 栈的压入.弹出序列 ? 总结上述入栈.出栈的过程,我们可以找到判断个序列是不是栈的弹出序列的规律:如果下一个弹出的数字刚好是栈顶数字,那么直接弹出. 如果下一个弹出的数字不在栈顶,我们把压栈序列中还没有入栈的数字压 入辅助栈,直到把下一个需要弹出的数字压入栈顶为止.如果所有的数字 都压入栈了仍然没有找到下一个弹出的数字,那么该序列不可能是一个弹出序列

【剑指offer】Q40:数组中出现一次的数

书里面关于分类的判断有些麻烦,通过某一位为0为1来对数组元素进行分类.假如第3位为1,那么也就是元素x & 8 等于或不等于0,所以没必要非的用第几位去判断. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return f

【Java】 剑指offer(17) 在O(1)时间删除链表结点

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 思路 通常那样从头开始查找删除需要的时间为O(n),要在O(1)时间删除某结点,可以这样实现:设待删除结点i的下一个结点为j,把j的值复制到i,再把i的指针指向j的下一个结点,最后删除j,效果就相当于删除j. 注意特殊情况:1.当待删除结点i为尾结点时,无下一个结点,则只能从头到尾顺序遍历:2.当链

剑指offer—第三章高质量代码(o(1)时间删除链表节点)

题目:给定单向链表的头指针和一个节点指针,定义一个函数在O(1)时间删除该节点,链表节点与函数的定义如下:struct ListNode{int m_nValue;ListNode* m_pValue;};void DeleteNode(ListNode** pListNode,ListNode * pToBeDeleted){} 思路:将要删除的节点的下一个节点的值赋值给i,删除下一个节点,但要考虑到删除的节点是最后一个节点并且该链表不止有一个节点的情况和该链表只有一个节点,该节点既是头节点也