剑指Offer第六天

原创 2018年04月16日 09:51:31

原题链接:

第一题:整数中1出现的次数(从1到n整数中1出现的次数)

题目:

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。

解析:

这个题目直接用常规的解法肯定太耗时间,要想到每一位和1的关系,拿5246,先是个位6,个位的变化范围是0~9,而这样的变化,会有524次,所以这里有524个1,又因为最后一次有个6,所以还要加一次,所以个位的1的个数是524+1 = 525,再看十位,十位上的数字是4,所以同理,这个位数的上的1的个数应该是52*10,注意这里不是52*1,因为,10位上的数后面10-20之间有十个1,且最后4>1,所以还要加上10,所以十位上的1的个数是52*10+10 = 530,这里要注意如果十位上的数字是1的话,就要看各位上的数是多少了,也就是10~20之间取多少个,这时候我们只要计算n%10+1就行了。然后同理推高位,可以得到1~5246中1的个数是(524*1+1)+(52*10+10)+(5*100+100) +(0*1000+1000) = 2655个。这是参照了大牛的解题思路代码如下:

public int NumberOf1Between1AndN_Solution(int n) {
        if(n < 1)return 0;
        int sum = 0,base = 1,round = n;
        while(round > 0) {
            int weight = round % 10;
            round /= 10;
            sum += round*base;
            if(weight > 1)sum += base;
            else if(weight == 1)sum += (n % base)+1;
            base *= 10;
        }
        return sum;
    }

第二题:把数组排成最小的数

题目:

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

解析

这个题目要想到字符串,想到一个排序规则,两个数a,b,把它们转换成字符串,把它们连起来,如果a+b > b+a(注意我这里+的意思是代表连起来),则我们要选择b+a,按照这个规则来排序,按照小的排在前面就行了。

public String PrintMinNumber(int[] numbers) {
        ArrayList<String>list = new ArrayList<String>();
        for(int i = 0; i < numbers.length; i++)list.add(numbers[i]+"");
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return (o1+o2).compareTo(o2+o1);  //按照降序排列(第一个大于第二个返回1-->升序排列)
            }
        });
        String str = "";
        for(String temp:list)str += temp;
        return str;
    }   

第三题:丑数

题目:

把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

解析:

这个题目按照直接一个个判断是不是丑数的方法不是好方法,要想到的是可以从小到大计算出丑数,存到一个数组中,这里要注意的是丑数的顺序要是从小到大的排列(因为等下要按照下标取),所以每次生成的时候,要选择最小的丑数生成,设置三个小标i2,i3,i5记录三个因子各自的下标,每次比较生成即可。

 public int GetUglyNumber_Solution(int index) {
        if(index == 0)return 0;
        int[] ans = new int[index+1];
        int count = 0,i2 = 0,i3 = 0,i5 = 0;
        ans[0] = 1;
        while(count < index) {
            int temp = Math.min(ans[i2]*2, Math.min(ans[i3]*3, ans[i5]*5));
            if(temp == ans[i2] * 2)i2++;
            if(temp == ans[i3] * 3)i3++;
            if(temp == ans[i5] * 5)i5++;
            ans[++count] = temp;
        }
        return ans[index-1];
    }

第一个只出现一次的字符

题目:

在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置。

解析:

直接用哈希表,一个计数数组记录每个字母出现的次数,两次O(n)的遍历,第二次从前往后判断,只要字母只出现一次就直接返回下标即可。

public int FirstNotRepeatingChar(String str) {
        if(str == null || str.length() == 0)return -1;
        int[] a = new int[59]; //65~122
        for(int i = 0; i < str.length(); i++)a[str.charAt(i)-'A'+1]++;
        for(int i = 0; i < str.length(); i++)if(a[str.charAt(i)-'A'+1] == 1)return i;
        return -1;
    }

    //熟悉一下HashMap的写法
    public int FirstNotRepeatingChar2(String str) {
        if(str == null || str.length() == 0)return -1;
        HashMap<Character,Integer> mp = new HashMap<Character,Integer>();
        for(int i = 0; i < str.length(); i++) {
            if(!mp.containsKey(str.charAt(i))) {
                mp.put(str.charAt(i), 1);
            }else {
                mp.put(str.charAt(i), mp.get(str.charAt(i))+1);
            }
        }
        for(int i = 0; i < str.length(); i++)if(mp.get(str.charAt(i)) == 1)return i;
        return -1;
    }

数组中的逆序对

题目:

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

解析:

这个题目用到归并排序,分开到底之后,每次合并,判断一下两个数的大小,如果左边的data[i] > data[j],那么逆序数,就可以加上j - mid(前面的(mid ~ j)都会比data[i] 要小),并且把data[i]加到辅助数组的后面,一步一步归并即可。

public int InversePairs(int[] data) {
        if (data.length == 0 || data == null)return 0;
        int[] temp = new int[data.length];
        int sum = Merge(temp, data, 0, data.length - 1);
        return sum;
    }

    public static int Merge(int[] temp, int[] data, int l, int r) {
        if (l == r) {// 递归条件
            temp[l] = data[l];
            return 0;
        }
        int mid = l + (r - l) / 2;
        int leftcount = Merge(temp, data, l, mid);
        int rightcount = Merge(temp, data, mid + 1, r);
        int i = mid, j = r, k = r,count = 0;
        while (i >= l && j > mid) {
            if (data[i] > data[j]) {
                count += j - mid;
                if(count >= 1000000007)count %= 1000000007; //这里很大的时候要去余
                temp[k--] = data[i--];
            } else {
                temp[k--] = data[j--];
            }
        }
        while (i >= l)temp[k--] = data[i--];
        while (j > mid)temp[k--] = data[j--];
        for(int p = l; p <= r; p++)data[p] = temp[p];  //把已经排序的数组考到原数组中
        return (count + leftcount + rightcount)%1000000007;
    }

两个链表的第一个公共结点

题目:

输入两个链表,找出它们的第一个公共结点。

解析:

关键就是要理解结点,而不是结点的值,一旦有一个结点相同,后面的都会相同
这里写图片描述

    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null)return null;
        int len1 = getListLength(pHead1),len2 = getListLength(pHead2);
        int lenDif = len1 - len2;
        ListNode pLong = pHead1,pShort = pHead2;
        if(len2 > len1) {
            pLong = pHead2;
            pShort = pHead1;
            lenDif = len2 - len1;
        }
        for(int i = 0; i < lenDif; i++)pLong = pLong.next;
        for(;pLong != pShort && pLong != null && pShort != null; pLong = pLong.next,pShort = pShort.next);
        return pLong;
    }
    private static int getListLength(ListNode node) {
        int len = 0;
        ListNode p = node;
        while(p != null) {
            p = p.next;
            len++;
        }
        return len;
    }

JAV基础第六天 (15-6-24)

1、数组的特点:数组是一个连续的内存空间;数组中的元素都是变量;数组变量中存放的是连续空间第一个元素的地址,数组元素下标从0开始,最大下标是长度-1;数组中元素的类型就是申明数组时定义的类型;数组创建...
  • BFQsong
  • BFQsong
  • 2015-06-24 23:06:20
  • 403

JavaWeb基础学习第六天

“/” ==“Web应用\WebRoot\WEB-INF\classes” “/” == “Web应用”public void doGet(HttpServletRequest request, H...
  • qq_21413417
  • qq_21413417
  • 2015-09-01 01:11:29
  • 219

淘淘商城第六天

1   课程计划 1、前台系统搭建 a)        Taotao-rest:服务层没有jsp页面 b)       Taotao-portal:门户,表现层。 2、首页分类列表展示 a)...
  • mathlpz126
  • mathlpz126
  • 2017-05-26 23:08:32
  • 363

剑指Offer 名企面试官精讲典型编程题(纪念版)-高清.............

  • 2018年04月09日 21:44
  • 54.05MB
  • 下载

十五天精通WCF——第一天 三种Binding(系列文章)

转眼wcf技术已经出现很多年了,也在.net界混的风生水起,同时.net也是一个高度封装的框架,作为在wcf食物链最顶端的我们所能做的任务已经简单的不能再简单了, 再简单的话马路上的大妈也能写wcf...
  • cqkxzyi
  • cqkxzyi
  • 2015-06-26 08:54:58
  • 677

剑指Offer 最新版

  • 2017年09月11日 10:38
  • 104.53MB
  • 下载

算法面试题 剑指offer

  • 2017年11月13日 09:54
  • 20.94MB
  • 下载

寒假第六天

距离回家还有五天; 按键控制数码管: #include /*void delay(unsigned char i) { unsigned char j,k; for(j ...
  • XuLujunCSDN
  • XuLujunCSDN
  • 2017-01-20 08:51:00
  • 131

实习第六天

来,看看我们今天又学了什么。           老师布置给我们的两章ppt中共有300-400多页,而我只看了30多页,幸好明天可能有台风,老师不来上课,那我明天努力地研究ppt好了。刚刚我才发现了...
  • qq_20725221
  • qq_20725221
  • 2015-07-08 22:51:17
  • 290

第六天:定义范围

  • toto1297488504
  • toto1297488504
  • 2016-07-07 21:51:58
  • 2916
收藏助手
不良信息举报
您举报文章:剑指Offer第六天
举报原因:
原因补充:

(最多只允许输入30个字)