LeetCode 06Z字形变换07整数反转
目錄
- Z字形變換
- 題意
- 分析
- 整數反轉
- 結語
Z字形變換
題意
題目描述
將一個給定字符串根據給定的行數,以從上往下、從左到右進行 Z 字形排列。
比如輸入字符串為 “LEETCODEISHIRING” 行數為 3 時,排列如下:
之后,你的輸出需要從左往右逐行讀取,產生出一個新的字符串,比如:“LCIRETOESIIGEDHN”。
請你實現這個將字符串進行指定行數變換的函數:
string convert(string s, int numRows);
示例 1:
輸入: s = “LEETCODEISHIRING”, numRows = 3
輸出: “LCIRETOESIIGEDHN”
示例 2:
輸入: s = “LEETCODEISHIRING”, numRows = 4
輸出: “LDREOEIIECIHNTSG”
解釋:
分析
對于這題該如何處理呢?首先要理解題意,它就是本來給一個字符串,然后要按照Z字形排列等到一個形狀,根據這個形狀按照從左往右的順序取值得到一個新的字符串。
法一模擬法:
既然這個字符串是固定的,那么我們是否可以模擬這個過程?
- of course you can 模擬。你可以定義一個二位數組,根據Z字形的這個排列規律,先向下(同時橫坐標不變),再向上(同時考慮橫坐標增加)一直到最后,然后對二維數組進行遍歷取值(不空的值。)
這樣當然可以,但是模擬真的有必要這么搞嘛?當然沒必要。二維數組占據太多無用的空間浪費內存。我們其實可以對內存進行優化考慮:
這樣只需要考慮上下兩個方向往集合中添加元素,最終就可以實現啦。不過在字符串疊加時候盡量不要使用String直接加,會很慢。這種方法只能干掉40%的人,一般般。
ac代碼為:
法二數學分析
上面的一種方法為模擬Z字形操作的整個流程,需要往里添加,取值也需要遍歷取值。我們能不能用另一種角度去思考問題呢?
因為每次只加一個字符,我們如果按照以下的思路看待這個問題(原字符串彎曲),從每一層看,能不能找到每一層有什么規律呢?
- 第一層是 0 6 12也就是 0 0+(n-1)*2 0+(n-1)*3
- 第二層兩個求位置關系,可不可以看成第一層每個位置-1和+1兩個位置(越界不考慮)?
- 第三層和第二層同理,看成第一層的-2和+2不越界的位置。
- 最后一層單獨考慮
這樣整個邏輯分析就完成了,可以根據位置添加元素進去再取值。ac的代碼如下:
public String convert(String s, int numRows) {if(numRows==1)return s;List<Character> list[]=new ArrayList[numRows];for(int i=0;i<numRows;i++){list[i]=new ArrayList<Character>();}//處理第一行最后一行for(int i=0;i<s.length();i+=(numRows-1)*2){list[0].add(s.charAt(i));if(i+numRows-1<s.length()){list[numRows-1].add(s.charAt(i+numRows-1));}}for(int i=0;i<s.length()+numRows;i+=(numRows-1)*2){for(int j=1;j<numRows-1;j++)//中間所有行{int index1=i-j;int index2=i+j;if(index1>=0&&index1<s.length())list[j].add(s.charAt(index1));if(index2>=0&&index2<s.length())list[j].add(s.charAt(index2));}}StringBuilder builder=new StringBuilder(); for(int i=0;i<numRows;i++){for(int j=0;j<list[i].size();j++){builder.append(list[i].get(j));}}return builder.toString();}但這種方法也只能干掉40%+的人,該如何優化呢?
- 首先,該方法先存到List[]再取,其實是遍歷兩次,其實大可不必這樣,我們可以在進行計算每一層的同時加入到結果中。
- 其次,由于邊界的問題我們需要考慮太多的邊界問題,我們對此對中間層的考慮優化,兩個節點位置通過計算這樣組合,可以優化邊界的if else判斷。
注意一些細節情況,最終ac的代碼為:
public static String convert2(String s, int numRows) {if(numRows==1)return s;//處理第一行StringBuilder builder=new StringBuilder();for(int i=0;i<s.length();i+=(numRows-1)*2){builder.append(s.charAt(i));}for(int i=1;i<numRows-1;i++){for(int j=0;j<s.length()+numRows;j+=(numRows-1)*2)//中間所有行{int index1=j+i;int index2=j+(numRows-1)*2-i;if(index1<s.length())builder.append(s.charAt(index1));if(index2<s.length())builder.append(s.charAt(index2));}}for(int i=numRows-1;i<s.length();i+=(numRows-1)*2){ builder.append(s.charAt(i));}return builder.toString();}最終的效果還行(偶爾三毫秒):
整數反轉
這題的話注意以下數組越界問題,可以用long類型處理最終再用整形處理。
主要有兩種處理方法,一個就是轉成字符串處理,第二個就是用數值處理。但是一般盡量不要用字符串處理比較慢。
ac代碼為:
public int reverse(int x) {if(x==0)return 0;String value=x+"";if(value.charAt(0)=='-')value=value.substring(1);StringBuilder sb=new StringBuilder();for(int i=value.length()-1;i>=0;i--){sb.append(value.charAt(i));}long num=Long.parseLong(sb.toString());if(x<0)num=-num;if(num<Integer.MIN_VALUE||num>Integer.MAX_VALUE){return 0;}return (int)num;}數值類型處理方式為:
public int reverse(int x) {if(x==0)return 0;long num=0;while (x%10==0) {x/=10;}int t;while (x!=0) {t=x%10;//各位num=num*10+t;x/=10;if(num>Integer.MAX_VALUE||num<Integer.MIN_VALUE)return 0;}return (int)num; }時間還行:
結語
本次兩題稍容易一些,再接再厲,注意方法的優化。
歡迎關注公眾號:bigsai,回復進群,一起打卡LeetCode!
總結
以上是生活随笔為你收集整理的LeetCode 06Z字形变换07整数反转的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode 05最长回文子串
- 下一篇: LeetCode 08字符串转整数09回