劍指offer java刷一遍
http://www.lxweimin.com/p/010410a4d419
清晰 https://www.zhihu.com/question/36914829
StringBuffer 和 StringBuilder
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*
*/
import java.util.Stack;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> stack = new Stack<>();
while (listNode != null) {
stack.push(listNode.val);
listNode = listNode.next;
}
ArrayList<Integer> list = new ArrayList<>();
while (!stack.isEmpty()) {
list.add(stack.pop());
}
return list;
}
}
兩個棧實現隊列
import java.util.Stack;
public class stack_queue {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}else {
return stack2.pop();
}
}
}
旋轉數組的最小元素
用二分法,二分法為了簡便可以一直使用 start + 1 < end,但需要判斷最后兩個元素值。
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array==null||array.length==0){
return 0;
}
int start = 0;
int end = array.length - 1;
int mid = 0;
while (start + 1 < end){
mid = start + (end - start) / 2;
if(array[mid] > array[end]){
start = mid + 1;
}else{
end = mid;
}
}
if(array[start] < array[end])
return array[start];
else
return array[end];
}
}
跳臺階問題
public class Solution {
public int JumpFloor(int target) {
if(target <= 2){
return target;
}
int pre = 2;
int prepre = 1;
int temp = 0;
for(int i=3;i<target+1;i++){
temp = pre;
pre = pre + prepre;
prepre = temp;
}
return pre;
}
}
1的個數
public int NumberOf1(int n) {
int count = 0;
if(n >= 0){
while(n!=0){
count = count + (n & 1);
n = (n>>1);
}
}else {
n = ~n;
while(n!=0){
count = count + (n & 1);
n = (n>>1);
}
count = 32 - count;
}
return count;
}
另一種巧妙方法
public class Solution {
public int NumberOf1(int n) {
int count = 0;
while(n!= 0){
count++;
n = n & (n - 1);
}
return count;
}
}
如果一個整數不為0,那么這個整數至少有一位是1。如果我們把這個整數減1,那么原來處在整數最右邊的1就會變為0,原來在1后面的所有的0都會變成1(如果最右邊的1后面還有0的話)。其余所有位將不會受到影響。
舉個例子:一個二進制數1100,從右邊數起第三位是處于最右邊的一個1。減去1后,第三位變成0,它后面的兩位0變成了1,而前面的1保持不變,因此得到的結果是1011.我們發現減1的結果是把最右邊的一個1開始的所有位都取反了。這個時候如果我們再把原來的整數和減去1之后的結果做與運算,從原來整數最右邊一個1那一位開始所有位都會變成0。如1100&1011=1000.也就是說,把一個整數減去1,再和原整數做與運算,會把該整數最右邊一個1變成0.那么一個整數的二進制有多少個1,就可以進行多少次這樣的操作。
算法提升篇
求連續子數組的最大和--動態規劃
public class maxSumofContinueArray {
public static int FindGreatestSumOfSubArray(int[] array) {
int max = array[0];
int preMax = 0;
for(int i=0;i<array.length;i++){
if(preMax >= 0)
preMax = preMax + array[i];
else
preMax = array[i];
if(preMax > max)
max = preMax;
}
return max;
}
public static void main(String [] args){
int[] data = {1,-2,3,10,-4,7,2,-5};
System.out.println(FindGreatestSumOfSubArray(data));
}
}
剪繩子
public class cutRope {
public static int maxCutting(int length){
if(length <= 1) return 0;
if(length < 4) return length - 1;
int []res = new int[length+1];
res[0] = 0;
res[1] = 1;
res[2] = 2;
res[3] = 3;
int max = 0;
int temp = 0;
for(int i=4; i<=length; i++){
max = 0;
for(int j=1;j<=i/2;j++){
temp = res[j]*res[i-j];
if(temp > max) max = temp;
}
res[i] = max;
}
return res[length];
}
}
數組翻譯成字符串
0對應a,25對應z,給定一個整數,看有多少種對應方式。動態規劃的典型問題。
public class numberToString {
public static int getTranslationCount(int number){
if(number < 0) return 0;
return getTranslationCount(Integer.toString(number));
}
public static int getTranslationCount(String number){
int pre = 1;
int prepre = 1;
int temp = 0, g = 1;
for(int i=number.length()-2;i>=0;i--){
if(Integer.parseInt(number.charAt(i)+""+number.charAt(i+1))<26 && number.charAt(i) != '0'){
g = 1;
} else{
g = 0;
}
temp = pre;
pre = pre + g*prepre;
prepre = temp;
}
return pre;
}
public static void main(String[] args){
System.out.println(getTranslationCount(1204));
}
}
最長不重復子串
public class maxLengthOfNoDup {
public static int longestSubstringWithoutdup(String str){
if(str==null || str.length()==0)
return 0;
int[] dp = new int[str.length()];
dp[0] = 1;
int max = 1;
for(int i=1;i<dp.length;i++){
int j=i-1;
for(;j>=i-dp[i-1];j--){
if(str.charAt(i) == str.charAt(j))
break;
}
dp[i] = i - j;
if(dp[i]>max)
max = dp[i];
}
return max;
}
public static void main(String[] args){
System.out.println(longestSubstringWithoutdup("arabcadecefr"));
}
}
關鍵在于這句的理解 (;j>=i-dp[i-1];j--)。
這道題還是需要認真理解,首先為什么不能夠直接從j=i-1一直遍歷到j=0,因為要保證遍歷的范圍是不重復的,比如[2,3,2,4,5,6],對4來說和前面三個都不相等,但是里面就有2重復,需要根據前面一個的最大范圍確定所能遍歷的范圍。遍歷到j=m時加入相等,則會停止,計算元素個數是i-j+1,這里沒有+1,因為for循環先對j進行了減1操作。
矩陣中的路徑(回溯)
public class PathInArray {
public static boolean hasPath(char[][] data, String str){
if(data==null || data.length==0 || str==null || str.length()==0)
return false;
int m = data.length;
int n = data[0].length;
boolean[][] visted = new boolean[m][n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
visted[i][j] = false;
}
}
boolean res;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
res = dfs(data,visted,i,j,str,0);
if(res)
return true;
}
}
return false;
}
private static boolean dfs(char[][] data,boolean[][] visted,int m, int n , String str, int pos){
if(pos==str.length()) return true;
if(m<0 || m >= data.length || n < 0 || n >= data[0].length)
return false;
if(visted[m][n] || data[m][n] != str.charAt(pos)) return false;
visted[m][n] = true;
boolean res = dfs(data,visted,m+1,n,str,pos+1) ||
dfs(data,visted,m-1,n,str,pos+1) ||
dfs(data,visted,m,n-1,str,pos+1) ||
dfs(data,visted,m,n+1,str,pos+1);
visted[m][n] = false;
return res;
}
public static void main(String[] args){
char[][] data = {
{'a','b','t','g'},
{'c','f','c','s'},
{'j','d','e','h'}
};
System.out.println(hasPath(data,"bfce"));
System.out.println(hasPath(data,"abfb"));
}
}
機器人的運動范圍
public class robotMoveRange {
public static int movingCount(int threshold, int cow, int row){
if(threshold < 0 || cow < 0 || row < 0)
return 0;
boolean[][] visted = new boolean[cow][row];
for(int i=0;i<cow;i++){
for(int j=0;j<row;j++){
visted[i][j] = false;
}
}
int count = 0;
dfs(count,threshold, visted, cow, row, 0, 0);
// 返回的count=0,出現問題。整數是傳值
return count;
}
public static void dfs(int count, int threshold, boolean[][] visted, int cow, int row, int m, int n){
if( m < 0 || m>=cow || n<0 || n>=row) return;
if(visted[m][n]) return;
visted[m][n] = true;
if(getDigitSum(m) + getDigitSum(n) <= threshold) {
count += 1;
System.out.println(count); //最終結果正確
}
dfs(count, threshold, visted, cow, row, m-1, n);
dfs(count, threshold, visted, cow, row, m+1, n);
dfs(count, threshold, visted, cow, row, m, n+1);
dfs(count, threshold, visted, cow, row, m, n-1);
}
public static int getDigitSum(int number){
int sum = 0;
while(number!=0){
sum += number % 10;
number /= 10;
}
return sum;
}
public static void main(String[] args){
System.out.println(movingCount(9,2,20));
}
}
上面的程序有一點問題。如何去改進。
public class robotMoveRange {
public static int movingCount(int threshold, int cow, int row){
if(threshold < 0 || cow < 0 || row < 0)
return 0;
boolean[][] visted = new boolean[cow][row];
for(int i=0;i<cow;i++){
for(int j=0;j<row;j++){
visted[i][j] = false;
}
}
int count = 0;
count = dfs(threshold, visted, cow, row, 0, 0);
// 返回的count=0,出現問題。整數是傳值
return count;
}
public static int dfs( int threshold, boolean[][] visted, int cow, int row, int m, int n){
if( m < 0 || m>=cow || n<0 || n>=row) return 0;
if(visted[m][n] || (getDigitSum(m) + getDigitSum(n) > threshold)) return 0;
visted[m][n] = true;
return dfs(threshold, visted, cow, row, m-1, n) +
dfs( threshold, visted, cow, row, m+1, n) +
dfs( threshold, visted, cow, row, m, n+1) +
dfs(threshold, visted, cow, row, m, n-1) + 1;
}
public static int getDigitSum(int number){
int sum = 0;
while(number!=0){
sum += number % 10;
number /= 10;
}
return sum;
}
public static void main(String[] args){
System.out.println(movingCount(9,2,20));
}
}
一個數的整數次方
public class xPowerN {
public static double mypower(double number, int n){
if(n==0) return 1;
if(n < 0){
double res = mypower(number,-n);
return 1.0/res;
}else {
double temp = mypower(number,n>>1);
if((n & 1)==1){
return temp * temp * number;
}else
return temp * temp;
}
}
public static double mypower2(double number, int n){
double res = 1;
int abs_n = Math.abs(n);
while(abs_n!=0){
if((abs_n & 1) == 1)
res *= number;
abs_n >>= 1;
number *= number;
}
if(number < 0) return 1.0/res;
else return res;
}
public static void main(String[] args){
double base = 2;
int n = 10;
System.out.println(mypower2(base, n));
}
}
遞歸和循環兩種基本思路。
排序鏈表刪除重復元素
import com.ListNode;
import java.util.List;
// 刪除排序鏈表重復節點,不保留
public class DeleteNodeInLinklist {
public static ListNode DeleteDupNode(ListNode node){
if(node==null || node.next==null)
return node;
ListNode dummy = new ListNode(-1);
dummy.next = node;
ListNode ptr = dummy;
while(node != null && node.next != null){
if(node.val != node.next.val){
node = node.next;
ptr = ptr.next;
}else {
while((node != null) && (node.next != null) && (node.val==node.next.val)){
node = node.next;
}
node = node.next;
ptr.next = node;
}
}
return dummy.next;
}
// 刪除重復節點但保留一個
public static ListNode DeleteDupNodeWithOne(ListNode node){
if(node==null || node.next==null)
return node;
ListNode current = node;
while(current != null && current.next != null){
if(current.val == current.next.val)
current.next = current.next.next;
else
current = current.next;
}
return node;
}
}
BFS
樹的按層遍歷
隊列相關知識 https://juejin.im/post/5a3763ed51882506a463b740
public class BTlevelOrderTravelsal {
public List<List<Integer>> levelOrder(TreeNode root){
List<List<Integer>> res = new ArrayList<>();
if(root == null) return res;
// LinkedList ?
Queue<TreeNode> nodes = new LinkedList<>();
nodes.offer(root);
while(!nodes.isEmpty()){
List<Integer> subres = new ArrayList<>();
int levelNum = nodes.size();
for(int i=0;i<levelNum;i++){
TreeNode node = nodes.poll();
subres.add(node.val);
if(node.left != null) nodes.offer(node.left);
if(node.right != null) nodes.offer(node.right);
}
res.add(subres);
}
return res;
}
}
之字形層次打印二叉樹
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
boolean order = true;
int size = 1;
while(!q.isEmpty()) {
List<Integer> tmp = new ArrayList<>();
for(int i = 0; i < size; ++i) {
TreeNode n = q.poll();
if(order) {
tmp.add(n.val);
} else {
tmp.add(0, n.val);
}
if(n.left != null) q.add(n.left);
if(n.right != null) q.add(n.right);
}
res.add(tmp);
size = q.size();
order = order ? false : true;
}
return res;
}
}
Remove Invalid Parentheses (leetcode 301)
https://leetcode.com/problems/remove-invalid-parentheses/description/
public class Solution {
public List<String> removeInvalidParentheses(String s) {
List<String> res = new ArrayList<>();
if (s == null){
return res;
}
Set<String> visited = new HashSet<>();
Queue<String> queue = new LinkedList<>();
queue.offer(s);
visited.add(s);
boolean found = false;
while (!queue.isEmpty()){
String item = queue.poll();
if(isVaild(item)){
res.add(item);
found = true;
}
if(found) continue;
for(int i=0; i<item.length();i++){
if(item.charAt(i) != '(' && item.charAt(i) !=')') continue;
String t = item.substring(0,i) + item.substring(i+1);
if(!visited.contains(t)){
queue.offer(t);
visited.add(t);
}
}
}
return res;
}
public static boolean isVaild(String s){
int count = 0;
for(int i=0; i<s.length();i++){
if(s.charAt(i)=='(') count += 1;
if(s.charAt(i)==')' && count-- == 0) return false;
}
return count == 0;
}
}