1. 程式人生 > >牛客幾個有意思的小題

牛客幾個有意思的小題

感覺以下幾個小問題有點意思,有些程式碼是自己寫的,有些則是總結別人或者引用別人的,程式碼可能有些不足或者其他解法以及優化,歡迎指出,一起進步。

   /**
    * 問題描述:一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。
    * 思路:使用set,如果集合中存在該元素則刪除,否則加入,最後元素只會剩下只出現一次的元素,得到結果。
    */
   public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
       Set<Integer> set = new
HashSet<Integer>(); for(int i = 0; i < array.length; i++){ //包含則刪除 if (set.contains(array[i])){ set.remove(array[i]); }else { set.add(array[i]); } } Integer[] temp = new Integer[2]; set.toArray(temp); num1[0
] = temp[0]; num2[0] = temp[1]; }
    /**
     * 獲得兩個整形二進位制表達位數不同的數量。
     * @param m 整數m
     * @param n 整數n
     * @return 整型
     */
    public int countBitDiff(int m, int n){
        //先進行異或處理,然後0替換掉,判斷長度
        String string = Integer.toBinaryString(m^n);
        string = string.replace("0"
, ""); return string.length(); }
    /**
     * 輸入兩個連結串列,找出它們的第一個公共結點。
     * 思路:遍歷第一個連結串列並將值儲存在map中,其次遍歷第二條連結串列,判斷該值是否存在map中,存在則返回。
     * @param pHead1
     * @param pHead2
     * @return ListNode
     */
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode currentOne = pHead1;
        ListNode currentTwo = pHead2;
        Map<ListNode, Integer> map = new HashMap<ListNode, Integer>();
        while (currentOne != null){
            //存入map
            map.put(currentOne, null);
            currentOne = currentOne.next;
        }
        while (currentTwo != null){
            //存在則返回第一個節點
            if (map.containsKey(currentTwo)){
                return currentTwo;
            }else {
                currentTwo = currentTwo.next;
            }
        }
        return null;
    }
    /**
     * 問題描述:假設一個球從任意高度自由落下,每次落地後反跳回原高度的一半;
     * 再落下, 求它在第5次落地時,共經歷多少米?第5次反彈多高?
     */
    public static void getJourney(int high)
    {
        double back = high;
        double sum = high;
        for(int i = 0; i < 5; i++){
            sum += back;
            back = back/2;
        }
        System.out.println(sum);
        System.out.println(back);
    }
    /**
     * 將一個字元中所有出現的數字前後加上符號“*”,其他字元保持不變。
     * 思路:在數字前後都加上*,最後將**替換掉。(看牛友的,感覺思路很棒)
     */
    public static String MarkNum(String pInStr)
    {
        StringBuffer stringBuffer = new StringBuffer();
        for(int i = 0; i < pInStr.length(); i++){
            if (pInStr.charAt(i) >= 48 && pInStr.charAt(i) <= 57){
                stringBuffer.append("*" + pInStr.charAt(i) + "*");
            }else {
                stringBuffer.append(pInStr.charAt(i));
            }
        }
        System.out.println(stringBuffer.toString());
        return stringBuffer.toString().replace("**", "");
    }
    /**
     * 找出字串中第一個只出現一次的字元,
     * 輸出第一個只出現一次的字元,如果不存在輸出-1。
     * 思路:使用map將字元作為key,出現次數作為value,很多字串的題都可以這樣做。
     */
    public static void PrintSingleChar(String string){
        Map<Character, Integer> map = new HashMap<Character, Integer>();
        for (int i = 0; i < string.length(); i++){
            if (map.containsKey(string.charAt(i))){
                //存在則次數加1
                map.put(string.charAt(i), map.get(string.charAt(i))+1);
            }else {
                //不存在則value=1
                map.put(string.charAt(i), 1);
            }
        }
        for (int i = 0; i < string.length(); i++){
            if (map.get(string.charAt(i)) == 1){
                System.out.println(string.charAt(i));
                return;
            }
        }
        System.out.println("-1");
    }
    /**
     * 輸入一個連結串列,輸出該連結串列中倒數第k個結點。
     * 思路:存入棧中,彈出k-1個數後返回k個。
     * 注意:棧不能為空,棧長度大等於k,k大於0,否則都返回null。
     */
    public ListNode FindKthToTail(ListNode head,int k) {
        ListNode temp = head;
        Stack<ListNode> stack = new Stack<ListNode>();
        //直接遍歷入棧
        while (temp != null){
            stack.push(temp);
            temp = temp.next;
        }
        if (!stack.isEmpty() && stack.size() >= k && k > 0){
            for (int i = k-1; i > 0; i--){
                stack.pop();
            }
            return stack.pop();
        }else {
            return null;
        }
    }
    /**
     * 求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?
     * 為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,
     * 但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,
     * 可以很快的求出任意非負整數區間中1出現的次數。
     * 思路:轉存字串陣列,遍歷。
     */
    public static int NumberOf1Between1AndN_Solution(int n) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i <= n; i++){
            stringBuffer.append(i);
        }
        int count = 0;
        for (int i = 0; i < stringBuffer.length(); i++){
            if(stringBuffer.charAt(i) == '1'){
                count++;
            }
        }
        return count;
    }
    /**
     * 統計一個數字在排序陣列中出現的次數。
     * 思路:二分法(看到牛友的解答,感覺很棒),不過必須在順序從小到大的情況下。
     */
    public static int GetNumberOfK(int [] array , int k) {
        int start = GetLower(array, k);
        int end = GetUper(array, k);
        return end - start + 1;
    }
    //獲取k第一次出現的下標
    public static int GetLower(int [] array , int k){
        int start = 0;
        int end = array.length-1;
        int mid = (start + end)/2;
        while (start <= end){
            if (array[mid] < k){
                start = mid + 1;
            }else {
                end = mid - 1;
            }
            mid = (start + end)/2;
        }
        return start;
    }
    //獲取k最後一次出現的下標
    public static int GetUper(int[] array, int k){
        int start = 0;
        int end = array.length-1;
        int mid = (start + end)/2;
        while (start <= end){
            if (array[mid] <= k){
                start = mid + 1;
            }else {
                end = mid - 1;
            }
            mid = (start + end)/2;
        }
        return end;
    }
    /**
     * 一個連結串列中包含環,請找出該連結串列的環的入口結點。
     * 思路:要尋找環的入口節點,遍歷節點的時候,遇到的第一個重複節點肯定入環節點,
     * 所以定義一個Set,新增失敗時即返回入口節點
     */
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if (pHead == null){
            return null;
        }else {
            Set<Integer> set = new HashSet<Integer>();
            ListNode listNode = pHead;
            while (listNode != null){
                if(!set.add(listNode.val)){
                    return listNode;
                }
                listNode = listNode.next;
            }
            return null;
        }
    }
    /**
     * 組合語言中有一種移位指令叫做迴圈左移(ROL),
     * 現在有個簡單的任務,就是用字串模擬這個指令的運算結果。對於一個給定的字元序列S,
     * 請你把其迴圈左移K位後的序列輸出。例如,字元序列S=”abcXYZdef”,要求輸出迴圈左移3位後的結果,
     * 即“XYZdefabc”。是不是很簡單?OK,搞定它!
     * @param str
     * @param n
     * @return
     */
    public static String LeftRotateString(String str,int n) {
        int count;
        //字串為空
        if (str.length() == 0){
            return "";
        }
        //字串不為空並且n大於字串長度
        if (n > str.length()){
            count = n%str.length(); //迴圈str長度倍的話,順序不變,所以取餘即可
        }else {
            count = n;
        }
        return str.substring(count) + str.substring(0, count);
    }
    /**
     * 給定兩個字串,請編寫程式,確定其中一個字串的字元重新排列後,能否變成另一個字串。
     * 這裡規定大小寫為不同字元,且考慮字串重點空格。
     * 給定一個string stringA和一個string stringB,請返回一個bool,代表兩串是否重新排列後可相同。
     * 保證兩串的長度都小於等於5000。
     * 思路:所有字元總數為256,定義兩個個256的陣列,下標分別表示字元的ASCII值,對應數值表示出現次數,
     * 統計AB字串後遍歷兩個陣列比較對應位置數值是否相同即可。
     * @param stringA
     * @param stringB
     * @return
     */
    public boolean checkSam(String stringA, String stringB) {
        //兩字串存在空的情況
        if (stringA == null || stringB == null){
            return false;
        }
        /**
         * 兩字串都不為空
         * 長度不相等則直接返回false
         */
        if (stringA.length() != stringB.length()){
            return false;
        }
        int[] strA = new int[256];
        int[] strB = new int[256];
        for(int i = 0; i < stringA.length(); i++){
            strA[stringA.charAt(i)]++;
            strB[stringB.charAt(i)]++;
        }
        //遍歷陣列所有元素,進行對比
        for (int i = 0; i < 256; i++){
            if (strA[i] != strB[i]){
                return false;
            }
        }
        return true;
    }
    /**
     * 利用字元重複出現的次數,編寫一個方法,實現基本的字串壓縮功能。
     * 比如,字串“aabcccccaaa”經壓縮會變成“a2b1c5a3”。若壓縮後的字串沒有變短,則返回原先的字串。
     * 給定一個string iniString為待壓縮的串(長度小於等於10000),保證串內字元均由大小寫英文字母組成,返回一個string,為所求的壓縮後或未變化的串。
     * @param iniString
     * @return
     */
    public static String zipString(String iniString) {
        StringBuffer stringBuffer = new StringBuffer();
        int count = 1;
        for(int i = 0; i < iniString.length()-1; i++){
            if(iniString.charAt(i) == iniString.charAt(i+1)){
                count++;
            }else{
                stringBuffer.append(iniString.charAt(i));
                stringBuffer.append(count);
                count = 1;
            }
        }
        //System.out.println("stringBuffer = " + stringBuffer.toString());
        stringBuffer.append(iniString.charAt(iniString.length()-1));
        stringBuffer.append(count);
        //System.out.println("s.length = " + stringBuffer.length() + ", s = " + stringBuffer.toString());
        if(stringBuffer.length() >= iniString.length()){
            return iniString;
        }else{
            return stringBuffer.toString();
        }
    }
    /**
     * 請編寫一個演算法,若N階方陣中某個元素為0,則將其所在的行與列清零。
     * 給定一個N階方陣int[][](C++中為vector<vector><int>>)mat和矩陣的階數n,
     * 請返回完成操作後的int[][]方陣,保證n小於等於300,矩陣中的元素為int範圍內。
     */
    public int[][] clearZero(int[][] mat, int n) {
        Set<Integer> setX = new HashSet<Integer>();
        Set<Integer> setY = new HashSet<Integer>();
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(mat[i][j] == 0){
                    setX.add(i);
                    setY.add(j);
                }
            }
        }
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(setX.contains(i) || setY.contains(j)){
                    mat[i][j] = 0;
                }
            }
        }
        return mat;
    }

好好做題,努力搬磚,總有一天能娶得起媳婦兒,年輕人,別亂想。