劍指offer 31-35

31.整數(shù)中1出現(xiàn)的次數(shù)

求出1~13的整數(shù)中1出現(xiàn)的次數(shù),并算出100~1300的整數(shù)中1出現(xiàn)的次數(shù)晒喷?
為此他特別數(shù)了一下1~13中包含1的數(shù)字有1孝偎、10、11凉敲、12衣盾、13因此共出現(xiàn)6次,但是對(duì)于后面問(wèn)題他就沒(méi)轍了。
ACMer希望你們幫幫他,并把問(wèn)題更加普遍化,可以很快的求出任意非負(fù)整數(shù)區(qū)間中1出現(xiàn)的次數(shù)(從1 到 n 中1出現(xiàn)的次數(shù))爷抓。

這個(gè)題在前面的一篇文章里面有寫(xiě)到過(guò)更普及的K出現(xiàn)的次數(shù)雨效,關(guān)鍵點(diǎn)有兩個(gè):
1.統(tǒng)計(jì)的是k出現(xiàn)的次數(shù),而不是包含k的數(shù)字的個(gè)數(shù)废赞,例如統(tǒng)計(jì)1出現(xiàn)的次數(shù),那么11出現(xiàn)了2次,因此可以直接采用對(duì)每一位進(jìn)行分析出現(xiàn)K的次數(shù)叮姑,然后把所有的結(jié)果相加即可唉地;
2.對(duì)每一位進(jìn)行分析的時(shí)候要分大于K据悔,小于K,等于K三種情況來(lái)討論耘沼,以n=31245,k=2為例
1這一位极颓,a=3,b=245,最大的是22999,因此可能結(jié)果為2000-2999,12000-12999,22000-22999群嗤,共a1000=3000個(gè)菠隆;
2這一位,a=31狂秘,b=45,前面的從0-30都沒(méi)問(wèn)題骇径,可以取31
100種,但當(dāng)前面為31時(shí)者春,只能取31200-31245共46種破衔,故共計(jì)3100+46=3146種;
4這一位钱烟,與小于K大致相同晰筛,但更多一些,a=312,b=5,那么從200-299,1200-1299,2200-2299....31200-31299均可拴袭,共(a+1)*10=3130種
按這個(gè)思路读第,把每一位出現(xiàn)K的可能加起來(lái)就是最后K出現(xiàn)的總次數(shù)
代碼如下

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        if(n<0){
            return 0;
        }
        //用copyn來(lái)設(shè)置循環(huán)中止的條件,每次循環(huán)都使得copyn = copyn/10;
        int copyn = n;
        //用cnt來(lái)記錄當(dāng)前的位置拥刻,如個(gè)位就是10的0次方位
        int cnt = 0;
        //用sum來(lái)記錄最后的結(jié)果
        int sum = 0;
        while(copyn!=0){
            copyn /= 10;
            //對(duì)于a,mid,b以312的2這一位為例
            //a = 312/10=31
            int a = n/(int)Math.pow(10,cnt+1);
            //mid = 312%10/1=2
            int mid = n%(int)Math.pow(10,cnt+1)/(int)Math.pow(10,cnt);
            //b = 312%10%1 = 0
            int b = n%(int)Math.pow(10,cnt+1)%(int)Math.pow(10,cnt);
            if(mid<1){
                sum += a*(int)Math.pow(10,cnt);
            }
            if(mid==1){
                sum += a*(int)Math.pow(10,cnt)+b+1;
            }
            if(mid>1){
                sum += (a+1)*(int)Math.pow(10,cnt);
            }
            cnt++;
        }
        return sum;
    }
}

32.把數(shù)組排成最小的數(shù)

輸入一個(gè)正整數(shù)數(shù)組怜瞒,把數(shù)組里所有數(shù)字拼接起來(lái)排成一個(gè)數(shù),打印能拼接出的所有數(shù)字中最小的一個(gè)泰佳。
例如輸入數(shù)組{3盼砍,32,321}逝她,則打印出這三個(gè)數(shù)字能排成的最小數(shù)字為321323浇坐。

這個(gè)題的思路就是比較給定數(shù)組中的任意兩個(gè)數(shù),例如3和32黔宛,由于323小于332近刘,所以32排在3前面,再比較3和321臀晃,由于3213小于3321觉渴,所以321排在3前面,最后比較32和321徽惋,由于32132小于32321案淋,所以321排在32前面,故排序大小順序?yàn)閇321,32,3]最后拼接起來(lái)得到的就是最后的結(jié)果险绘,即最小的數(shù)321323,由于考慮整數(shù)可能越界踢京,而且整數(shù)拼接起來(lái)可能比較麻煩誉碴,因此這里采用字符串進(jìn)行操作,且在對(duì)字符串進(jìn)行排序的時(shí)候用到lamda表達(dá)式瓣距;
代碼如下

import java.util.Arrays;

public class Solution {
    public String PrintMinNumber(int [] numbers) {
        if(numbers==null||numbers.length==0){
            return "";
        }
        //用一個(gè)字符串?dāng)?shù)組存儲(chǔ)所有數(shù)字轉(zhuǎn)化成的字符串
        String[] nums = new String[numbers.length];
        for(int i=0;i<numbers.length;i++){
            //+""代表轉(zhuǎn)化為字符串
            nums[i] = numbers[i]+"";
        }
        //這里使用Arrays.sort進(jìn)行排序時(shí)用來(lái)了lambda表達(dá)式
        //即將s1+s2和s2+s1進(jìn)行升序排列
        Arrays.sort(nums,(s1,s2)->(s1+s2).compareTo(s2+s1));
        //最后將全部結(jié)果拼接起來(lái)黔帕,得到最后的輸出
        String res = "";
        for(String s:nums){
            res += s;
        }
        return res;
    }
}

33.丑數(shù)

把只包含質(zhì)因子2、3和5的數(shù)稱作丑數(shù)(Ugly Number)蹈丸。
例如6成黄、8都是丑數(shù),但14不是逻杖,因?yàn)樗|(zhì)因子7奋岁。 
習(xí)慣上我們把1當(dāng)做是第一個(gè)丑數(shù)。求按從小到大的順序的第N個(gè)丑數(shù)弧腥。

該題的核心思想就是新的丑數(shù)依然是由老的丑數(shù)構(gòu)成的厦取,我們需要建立一個(gè)新的數(shù)組不斷存儲(chǔ)新加入的丑數(shù),然后用三個(gè)指針指向2,3,5所在的該丑數(shù)數(shù)組的位置管搪,然后用2,3,5指針?biāo)傅奈恢玫某髷?shù)分別去乘以2,3,5選擇最小的虾攻,然后使得構(gòu)成這個(gè)新丑數(shù)的這個(gè)數(shù)的指針向后移動(dòng)一位,如果相同更鲁,則同時(shí)移動(dòng)一位霎箍,例如23和32,則index_2和index_3同時(shí)后移一位澡为;
代碼如下

public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if(index<=0){
            return 0;
        }
        //用3個(gè)指針指向2,3,5指向的丑數(shù)數(shù)組中的位置
        int index_2 = 0,index_3 = 0,index_5 = 0;
        int[] ugly_nums = new int[index];
        ugly_nums[0] = 1;
        for(int i=1;i<index;i++){
            //選擇最小的最為新丑數(shù)
            ugly_nums[i] = Math.min(Math.min(ugly_nums[index_2]*2,ugly_nums[index_3]*3),Math.min(ugly_nums[index_2]*2,ugly_nums[index_5]*5));
            int t2 = ugly_nums[i]/2,t3 = ugly_nums[i]/3,t5 = ugly_nums[i]/5;
            //判斷哪個(gè)指針需要后移
            if(t2==ugly_nums[index_2]){
                index_2++;
            }
            if(t3==ugly_nums[index_3]){
                index_3++;
            }
            if(t5==ugly_nums[index_5]){
                index_5++;
            }
        }
        //返回丑數(shù)數(shù)組總最后一個(gè)元素為第index個(gè)丑數(shù)
        return ugly_nums[index-1];
        
    }
}

34.第一個(gè)只出現(xiàn)一次的字符

在一個(gè)字符串(0<=字符串長(zhǎng)度<=10000漂坏,全部由字母組成)中找到第一個(gè)只出現(xiàn)一次的字符,
并返回它的位置, 如果沒(méi)有則返回 -1(需要區(qū)分大小寫(xiě)).

本題最直觀的就是用hashmap來(lái)統(tǒng)計(jì)字符出現(xiàn)的次數(shù),也可以建立一個(gè)整數(shù)數(shù)組媒至,通過(guò)將字符轉(zhuǎn)化為ASCII碼顶别,然后整數(shù)數(shù)組對(duì)應(yīng)位置上加一,然后再遍歷原字符串或轉(zhuǎn)化為的字符數(shù)組拒啰,返回第一個(gè)在整數(shù)數(shù)數(shù)組中為1的值
流程為

1.將String轉(zhuǎn)為一個(gè)字符數(shù)組c驯绎,如“abc”--->{‘a(chǎn)’,‘b’,‘c’};
2.建立一個(gè)容量為256的整型數(shù)組arr,每一位的下標(biāo)對(duì)應(yīng)著ASCII值
3.遍歷字符數(shù)組c,例如遍歷到了'a'谋旦,那么就在arr[(int)'a']的位置對(duì)應(yīng)的值+1
4.最后再遍歷一遍c剩失,找到第一個(gè)在arr中的值為1的那個(gè)字符,例如遍歷到了'a'且arr[int(a)]==1,那么就返回這個(gè)'a'所在的位置即可

代碼如下

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        if(str.length()==0||str==null){
            return -1;
        }
        //將String轉(zhuǎn)化為字符數(shù)組
        char[] arr = str.toCharArray();
        //建立一個(gè)整型數(shù)組册着,作用類似于hashmap拴孤,其中res的下標(biāo)i--->字符的ASCII值
        int[] res = new int[256];
        //遍歷一遍arr,使res中對(duì)應(yīng)位置的hash值加一
        for(char c:arr){
            res[(int)c]++;
        }
        //找到第一個(gè)hash值為1的字符甲捏,輸出它的位置
        for(int i=0;i<arr.length;i++){
            if(res[(int)arr[i]]==1){
                return i;
            }
        }
        return -1;
    }
}

35.數(shù)組中的逆序?qū)?/p>

在數(shù)組中的兩個(gè)數(shù)字演熟,如果前面一個(gè)數(shù)字大于后面的數(shù)字,則這兩個(gè)數(shù)字組成一個(gè)逆序?qū)Α?輸入一個(gè)數(shù)組,求出這個(gè)數(shù)組中的逆序?qū)Φ目倲?shù)P司顿。
并將P對(duì)1000000007取模的結(jié)果輸出绽媒。 即輸出P%1000000007

該題的思路就是使用歸并排序蚕冬,就是通過(guò)遞歸將數(shù)組拆分為最小的依次相鄰的兩個(gè)單元,然后用兩個(gè)指針?lè)謩e指向左右數(shù)組的頭部是辕,若左邊指針指向的元素大于右邊指針指向的元素,那么在左邊數(shù)組中指針指向的元素后面的數(shù)全部都大于右邊數(shù)組中指針指向的元素猎提,這些全部都構(gòu)成逆序?qū)袢瑲w并排序中我們還需要一個(gè)輔助數(shù)組去存儲(chǔ)順序大小排列好的元素,這才叫做歸并锨苏,最后統(tǒng)計(jì)所有這些逆序?qū)Ω斫蹋褪俏覀冃枰慕Y(jié)果,注意不要超出界限伞租。
代碼如下

public class Solution {
    //防止cnt溢出所以用一個(gè)long類型
    private long cnt = 0;
    private int[] tmp;  

    public int InversePairs(int[] nums) {
        tmp = new int[nums.length];
        mergeSort(nums, 0, nums.length - 1);
        return (int)(cnt % 1000000007);
    }

    private void mergeSort(int[] nums, int l, int h) {
        if (h - l < 1)
            return;
        //求出中值分界線
        int m = l + (h - l) / 2;
        //歸并排序贞谓,這里采用遞歸,可以想象葵诈,第一次遞歸到最結(jié)尾的時(shí)候
        //一個(gè)長(zhǎng)度為2的數(shù)組裸弦,對(duì)左右繼續(xù)遞歸都只有一個(gè)元素了,因此直接return
        //然后再執(zhí)行merge這個(gè)函數(shù)作喘,此時(shí)長(zhǎng)度為2,相當(dāng)于最小的一個(gè)子單元的歸并排序
        mergeSort(nums, l, m);
        mergeSort(nums, m + 1, h);
        merge(nums, l, m, h);
    }

    private void merge(int[] nums, int l, int m, int h) {
        //指針i指向左邊數(shù)組的頭部理疙,j指向右邊數(shù)組的頭部,k指向輔助數(shù)組的當(dāng)前元素位置,
        //我們要將兩個(gè)數(shù)組中的元素依次比較大小泞坦,然后存入輔助數(shù)組中
        //再將原數(shù)組中從l到h的所有元素替換為輔助數(shù)組中從l到h的所有元素
        int i = l, j = m + 1, k = l;
        //這里不用&&而用||是因?yàn)榭赡茏笥抑心硞€(gè)數(shù)組的指針走到頭了
        //那么此時(shí)我們需要做的就是把另外一個(gè)數(shù)組的所有元素替換到輔助數(shù)組中
        //因此while中是并列的四個(gè)條件
        while (i <= m || j <= h) {
            if (i > m)
                tmp[k] = nums[j++];
            else if (j > h)
                tmp[k] = nums[i++];
            else if (nums[i] <= nums[j])
                tmp[k] = nums[i++];
            else {
                tmp[k] = nums[j++];
                //這里是說(shuō)窖贤,當(dāng)左邊的某個(gè)元素大于右邊的元素的時(shí)候
                //那么左邊數(shù)組中這個(gè)元素后的所有元素都大于當(dāng)前右邊指向的這個(gè)元素
                //統(tǒng)計(jì)左邊數(shù)組中這個(gè)元素后的所有元素的個(gè)數(shù)就是我們要求的逆序?qū)?                this.cnt += m - i + 1;
            }
            k++;
        }
        for (k = l; k <= h; k++)
            nums[k] = tmp[k];
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市贰锁,隨后出現(xiàn)的幾起案子赃梧,更是在濱河造成了極大的恐慌,老刑警劉巖豌熄,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件授嘀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡房轿,警方通過(guò)查閱死者的電腦和手機(jī)粤攒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)囱持,“玉大人夯接,你說(shuō)我怎么就攤上這事》鬃保” “怎么了盔几?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)掩幢。 經(jīng)常有香客問(wèn)我逊拍,道長(zhǎng)上鞠,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任芯丧,我火速辦了婚禮芍阎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缨恒。我一直安慰自己谴咸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布骗露。 她就那樣靜靜地躺著岭佳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪萧锉。 梳的紋絲不亂的頭發(fā)上珊随,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音柿隙,去河邊找鬼叶洞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛优俘,可吹牛的內(nèi)容都是我干的京办。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼帆焕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼惭婿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起叶雹,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤财饥,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后折晦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體钥星,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年满着,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谦炒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡风喇,死狀恐怖宁改,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情魂莫,我是刑警寧澤还蹲,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響谜喊,放射性物質(zhì)發(fā)生泄漏潭兽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一斗遏、第九天 我趴在偏房一處隱蔽的房頂上張望山卦。 院中可真熱鬧,春花似錦最易、人聲如沸怒坯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至视译,卻和暖如春嬉荆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酷含。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工鄙早, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人椅亚。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓限番,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親呀舔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弥虐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 在C語(yǔ)言中,五種基本數(shù)據(jù)類型存儲(chǔ)空間長(zhǎng)度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來(lái)閱讀 3,352評(píng)論 0 2
  • 選擇題部分 1.()部門負(fù)責(zé)日常監(jiān)督檢查工作,安全巡視的同時(shí)進(jìn)行消防檢查,推動(dòng)消防安全制度的貫徹落實(shí)。 A: 消防...
    skystarwuwei閱讀 15,319評(píng)論 0 3
  • 專業(yè)考題類型管理運(yùn)行工作負(fù)責(zé)人一般作業(yè)考題內(nèi)容選項(xiàng)A選項(xiàng)B選項(xiàng)C選項(xiàng)D選項(xiàng)E選項(xiàng)F正確答案 變電單選GYSZ本規(guī)程...
    小白兔去釣魚(yú)閱讀 9,014評(píng)論 0 13
  • 咳嗽感冒愛(ài)上了你 沒(méi)日沒(méi)夜地糾纏不清 人家高高興興跨年迎元旦 而你每天發(fā)高燒打針忙 為娘心疼啊 一天半夜醒來(lái)看你臉...
    愛(ài)上一葉浮萍閱讀 389評(píng)論 14 24
  • 分享: 企業(yè)做大媚赖,必須把人搞透霜瘪。 企業(yè)無(wú)法做大的核心原因在于:無(wú)法把員工留在身邊。人比錢值錢惧磺,有人就會(huì)有錢颖对。 80...
    創(chuàng)新你的創(chuàng)造閱讀 66評(píng)論 0 1