20201014:演算法題+筆試題

明天,你好呀發表於2020-10-14

錯題一

  • 以下哪一項正則能正確的匹配網址: http://www.bilibili.com/video/av21061574()

在這裡插入圖片描述
正規表示式的規則:

規則字元在java.util.regex Pattern類中
A:字元
	x 字元 x。舉例:'a'表示字元a
	\\ 反斜線字元。
	\n 新行(換行)符 ('\u000A') 
	\r 回車符 ('\u000D')
B:字元類
	[abc] a、b 或 c(簡單類) 
	[^abc] 任何字元,除了 a、b 或 c(否定) 
	[a-zA-Z] a到 z 或 A到 Z,兩頭的字母包括在內(範圍) 
	[0-9] 09的字元都包括
C:預定義字元類
	. 任何字元。我的就是.字元本身,怎麼表示呢? \.
	\d 數字:[0-9]
	\w 單詞字元:[a-zA-Z_0-9]
		在正規表示式裡面組成單詞的東西必須有這些東西組成
	\s 匹配空格字元	
D:邊界匹配器
	^ 行的開頭 
	$ 行的結尾 
	\b 單詞邊界
		就是不是單詞字元的地方。
		舉例:hello world?haha;xixi
E:Greedy 數量詞 
	X? X,一次或一次也沒有 比如""空串 就是沒有
	X* X,零次或多次  大於等於1次 都算多次
	X+ X,一次或多次
	X{n} X,恰好 n 次 
	X{n,} X,至少 n 次 
	X{n,m} X,至少 n 次,但是不超過 m 次 

\w還包括數字在內,但是雙斜槓後面不能含有數字;

錯題二

  • 設int x=1,float y=2,則表示式x/y的值是:()

在這裡插入圖片描述

就本題而言,結果是float型別的,因為x,y兩個數字精度最高的就是float,所以最終結果是0.5,並且這個0.5是float型別的;

錯題三

public class Test {
    private static int j = 0;
 
    private static Boolean methodB(int k) {
        j += k;
        return true;
    }
 
    public static void methodA(int i) {
        boolean b;
        b = i < 10 | methodB(4);
        b = i < 10 || methodB(8);
 
    }
 
    public static void main(String args[]) {
        methodA(0);
        System.out.println(j);
    }
}
What is the result?

在這裡插入圖片描述

"|"是按位或:先判斷條件1,不管條件1是否可以決定結果(這裡決定結果為true),都會執行條件2;
"||"是邏輯或:先判斷條件1,如果條件1可以決定結果(這裡決定結果為true),那麼就不會執行條件2,具有短路的特點;

題目四

在這裡插入圖片描述

web容器:給處於其中的應用程式元件(JSP,SERVLET)提供一個環境,使 JSP、SERVLET直接與容器中的環境變數互動,不必關注其它系統問題。主要由WEB伺服器來實現。例如:TOMCAT、WEBLOGIC、WEBSPHERE等。該容器提供的介面嚴格遵守J2EE規範中的WEB APPLICATION 標準。我們把遵守以上標準的WEB伺服器就叫做J2EE中的WEB容器。

  • EJB容器:Enterprise java bean 容器。更具有行業領域特色。它提供給執行在其中的元件EJB各種管理功能。只要滿足J2EE規範的EJB放入該容器,馬上就會被容器進行高效率的管理。並且可以通過現成的介面來獲得系統級別的服務。例如郵件服務、事務管理。

  • JNDI:(Java Naming & Directory Interface)JAVA命名目錄服務。主要提供的功能是:提供一個目錄系,讓其它各地的應用程式在其上面留下自己的索引,從而滿足快速查詢和定位分散式應用程式的功能。

  • JMS:(Java Message Service)JAVA訊息服務。主要實現各個應用程式之間的通訊。包括點對點和廣播。

  • JTA:(Java Transaction API)JAVA事務服務。提供各種分散式事務服務。應用程式只需呼叫其提供的介面即可。

  • JAF:(Java Action FrameWork)JAVA安全認證框架。提供一些安全控制方面的框架。讓開發者通過各種部署和自定義實現自己的個性安全控制策略。

  • RMI / IIOP:(Remote Method Invocation /internet物件請求中介協議)他們主要用於通過遠端呼叫服務。例如,遠端有一臺計算機上執行一個程式,它提供股票分析服務,我們可以在本地計算機上實現對其直接呼叫。當然這是要通過一定的規範才能在異構的系統之間進行通訊。RMI是JAVA特有的。

錯題五

下面的輸出結果是什麼?

public class Demo {
  public static void main(String args[])
  {
    String str=new String("hello");
    if(str=="hello")
    {
      System.out.println("true");
    }      
    else     {
      System.out.println("false");
    }
  }
}

在這裡插入圖片描述

對於引用型別資料,使用==比較的是地址值;對於基本型別的資料,==號比較的是數值;
Java中使用new String("hello")時,JVM會先使用常量池來管理"hello"常量,再呼叫String類的構造器建立一個新的String物件,新建立的物件被儲存在堆記憶體中;而直接使用"hello"的字串常量,JVM會用常量池來管理這些字串。故上述程式中str=="hello"返回結果為false;

演算法題一

  • 給定僅有小寫字母組成的字串陣列 A,返回列表中的每個字串中都顯示的全部字元(包括重複字元)組成的列表。例如,如果一個字元在每個字串中出現 3 次,但不是 4 次,則需要在最終答案中包含該字元 3 次,你可以按任意順序返回答案:
示例 1:
輸入:["bella","label","roller"]
輸出:["e","l","l"]

示例 2:
輸入:["cool","lock","cook"]
輸出:["c","o"]
 
提示:
1 <= A.length <= 100
1 <= A[i].length <= 100
A[i][j] 是小寫字母

自己的做法:

public List<String> commonChars(String[] A) {
    //用於存放返回值
    ArrayList arrayList = new ArrayList<>();

    //1、先把給定的字串中第一個字串的所有字元放在結果集中
    //2、把索引從1開始的這些字串儲存為一個List,最後將他們整體存入一個List
    LinkedList<LinkedList<Character>> lists = new LinkedList<>();
    
    for (int i = 0; i < A.length; i++) {
        if (i == 0) {
            for (int k = 0; k < A[0].length(); k++) {
                arrayList.add(A[0].charAt(k));
            }
        } else {
            LinkedList<Character> characters = new LinkedList<>();
            for (int j = 0; j < A[i].length(); j++) {
                characters.add(A[i].charAt(j));
            }
            lists.add(characters);
        }
    }

    //System.out.println(lists);
    //[[l, a, b, e, l], [r, o, l, l, e, r]]

    //3、把索引為 1 以後的字串都放在集合裡面,如果集合中不能同時擁有結果集中的某個字元,就將這個字元移出結果集
    // 如果同時擁有一個字元,就將結果集中的字元保留,然後移除字串集合中的該字元

    for (int i = 0; i < arrayList.size(); i++) {
        for (int j = 0; j < lists.size(); j++) {
            //如果字串集合中不包含結果集中的當前字元
            if (!lists.get(j).contains(arrayList.get(i))) {
                //結果集中需要移除這個字元,然後跳出內迴圈,直接進行下一個結果集字元的判斷
                arrayList.remove(arrayList.get(i));
                i--;
                break;
            } else {
                lists.get(j).remove(arrayList.get(i));
            }
        }
    }
    System.out.println(arrayList);
    return arrayList;
}

自己的做法相對來說比較冗餘,時間和空間上開銷都比較大,學習了官方的解題之後,程式碼如下:

官網做法:

public static List<String> commonChars1(String[] A) {
    int[] minfreq = new int[26];
    Arrays.fill(minfreq, Integer.MAX_VALUE);

    for (String word : A) {
        int[] freq = new int[26];
        for (int i = 0; i < word.length(); i++) {
            ++freq[word.charAt(i) - 'a'];
        }
        for (int i = 0; i < 26; i++) {
            minfreq[i] = Math.min(minfreq[i], freq[i]);
        }
    }

    //System.out.println(Arrays.toString(minfreq));
    
    List<String> list = new ArrayList<>();
    for (int i = 0; i < 26; i++) {
        for (int j = 0; j < minfreq[i]; j++) {
            list.add(String.valueOf((char) (i + 'a')));
        }
    }

    return list;
}

【總結】:
1、定義一個長度為26的整型陣列,陣列中預設值全部為整型的最小值;
2、遍歷給定字串陣列中的每一個字串,把字串中出現的字元個數統計到另一個長度為26的整型陣列中;
3、比較最小統計個數陣列與當前字串統計字元得到的陣列,把最小的值存入最小統計個數的陣列,這樣下來minfreq陣列中存放的是所有字串中最小的統計個數;
4、最終遍歷這個統計陣列,將其中的字元個數大於等於1的字元依次新增進結果集集合中;


這個做法很新穎,核心是通過計算字元的在每個字串中的個數,最終生成結果集;

演算法題二

自己的做法:

public static int romanToInt(String s) {
    LinkedHashMap<Character, Integer> hashMap = new LinkedHashMap<>();
    hashMap.put('I', 1);
    hashMap.put('V', 5);
    hashMap.put('X', 10);
    hashMap.put('L', 50);
    hashMap.put('C', 100);
    hashMap.put('D', 500);
    hashMap.put('M', 1000);

    Integer sum = 0;
    for (int i = 0; i < s.length(); i++) {
        String regx = "IV|IX|XL|XC|CD|CM";
        if (i < s.length() - 1 && s.substring(i, i + 2).matches(regx)) {
            sum += (hashMap.get(s.charAt(i + 1)) - hashMap.get(s.charAt(i)));
            i++;
        } else {
            sum += hashMap.get(s.charAt(i));
        }
    }

    //System.out.println(sum);
    return sum;
}

【思路】:
1、首先使用鍵值對集合儲存羅馬數字及其對應的數字大小,這樣便於存取;
2、遍歷得到的這個字串,如果他不是倒數第二個字元並且它與後面的字元組成特定的集合,它們的總和就是它們之差;
3、如果不符合上面的條件,讓結果+=該羅馬字元對應的數字;
4、最終返回總和;

更高效的演算法:

public static int romanToInt1(String s) {
    int sum = 0;
    int preNum = getValue(s.charAt(0));
    for (int i = 1; i < s.length(); i++) {
        int num = getValue(s.charAt(i));
        if (preNum < num) {
            sum -= preNum;
        } else {
            sum += preNum;
        }
        preNum = num;
    }
    sum += preNum;
    return sum;
}

private static int getValue(char ch) {
    switch (ch) {
        case 'I':
            return 1;
        case 'V':
            return 5;
        case 'X':
            return 10;
        case 'L':
            return 50;
        case 'C':
            return 100;
        case 'D':
            return 500;
        case 'M':
            return 1000;
        default:
            return 0;
    }
}
  • 按照題目的描述,可以總結如下規則:

1、羅馬數字由 I,V,X,L,C,D,M 構成;
2、當小值在大值的左邊,則減小值,如 IV=5-1=4
3、當小值在大值的右邊,則加小值,如 VI=5+1=6
4、由上可知,右值永遠為正,因此最後一位必然為正。


演算法相對來說很簡單,只需要判斷當前遍歷到的羅馬數字和之前的保留數字大小,如果小的在前,大的在後就做減法,否則做加法;

相關文章