我的解法如下:
class Solution {
public String reverseLeftWords(String s, int n) {
Solution solution = new Solution();
char value;
char [] stringArr = s.toCharArray();//首先將String類型的s轉變爲char數組
int length = stringArr.length;
for (int i = 0; i <n ; i++) {
value = stringArr[0];
stringArr[0] = 0;
solution.move(stringArr);
stringArr[length-1] = value;
}
String out = String.valueOf(stringArr);
return out;
}
public void move(char[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] != 0) {
arr[i] = arr[i + 1];
}else{
arr[i] = 0;
break;
}
}
}
}
問題:速度慢,繁瑣,原始
這裏總結我這道題時出現的問題或者細節:
1.char和string的區別:
1. char是表示的是字符,定義的時候用單引號,只能存儲一個字符。例如; char='d'. 而String表示的是字符串,定義的時候用雙引號,可以存儲一個或者多個字符。例如:String=“we are neuer”。
2. char是基本數據類型,而String是個類,屬於引用數據類型。String類可以調用方法,具有面向對象的特徵。
2.在靜態的方法中不能直接調用非靜態的方法或屬性
解決辦法:
1. 將被調用的方法設置成靜態方法;
2. new本類,然後通過實例來調用。
3.將字符串和字符串數組互相轉換方法
java可以使用兩種方法直接將字符數組轉爲字符串
方法1:直接在構造String時轉換。
char[] data = {‘a’, ‘b’, ‘c’};
String str = new String(data);
方法2:調用String類的方法轉換。
String.valueOf(char[] ch)
java可以使用兩種方法直接將字符串轉爲字符數組
情況一:如果是有分隔符的那種例如”abc,def,ghi”;就直接分割就行了.
String string = “abc,def,ghi”;
String [] strArr= string.split(“,”); //注意分隔符是需要轉譯
情況二:如果是”abcdefghijk”這種字符串,就直接
String string1 = “abcdefghijk” ;
char [] strArr1 = string1.toCharArray(); //注意返回值是char數組
我見到最簡單解法如下:
class Solution {
public String reverseLeftWords(String s, int n) {
String str1=s.substring(0,n);
String str2=s.substring(n);
StringBuilder sb=new StringBuilder();
sb.append(str2).append(str1);
return sb.toString();
}
}
1.substring() 方法返回字符串的子字符串。 簡單說就是切割字符串
public String substring(int beginIndex) 或 public String substring(int beginIndex, int endIndex)
begin是包括,end不包括
2.StringBuilder類和StringBuffer類非常像,前者速度快,應用廣,但是後者在考慮線程安全的時候使用。
轉載一個別人總結的:https://blog.csdn.net/x83853684/article/details/82081658
2.
我的解法:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.lang.Math;
class Solution {
public int[] printNumbers(int n) {
List<Integer> list=new ArrayList<Integer>();
for (int i = 1; i < Math.pow(10,n); i++) {
list.add(i);
}
int[] outer = new int[list.size()];
for (int i = 0; i <list.size() ; i++) {
outer[i] = list.get(i);
}
return outer;
}
}
我這個可以優化的地方:普通數組是無法在創建之後,更改長度的,所以我選用了ArrayList,但是爲什麼我們不能在獲取n之後就計算出數組應該存入多少數據呢?
怎麼樣去避免使用Math.pow這個函數呢,下面的解法在時間大幅度提升。
class Solution {
public int[] printNumbers(int n) {
int sum = 9;
while(n > 1){
sum = sum * 10 + 9;
n--;
}
int[] arr = new int[sum];
for(; sum > 0;){
arr[sum - 1] = sum--;
}
return arr;
}
}
3.
這裏直接上題解:使用快慢指針
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode slow = head, fast = head;
for (int i = 0; i < k; i++)
fast = fast.next;
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
讓快指針先走K步,再讓他們倆同時走,這樣我們就能保證快指針擁有領先慢指針K步,所以當快指針走完時,慢指針就指向倒數第K個指針。
轉載一個快慢節點的應用:https://www.jianshu.com/p/21b4b8d7d31b
4.
總體難度不大,我的解法有點投機:
class Solution {
public String replaceSpace(String s) {
return s.replace(" ", "%20");
}
}
直接調用JAVA lang包下的replace方法,將空格替換成“%20”
看答案還有一種複雜一點:
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for(int i = 0;i<s.length();i++) {
if(s.charAt(i) == ' ') {
sb.append("%20");
}else {
sb.append(s.charAt(i));
}
}
return sb.toString();
這裏補充一個打印數組的知識點:
三種打印數組的方法:1.for循環遍歷 2.增強for循環 3.調用Array.tostring()方法
https://blog.csdn.net/chenkaibsw/article/details/78989459
5.
答案一:
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode node = helper(root);
return node;
}
public TreeNode helper(TreeNode root){
if(root == null){
return null;
}
TreeNode mid = root.left;//中轉來儲存你的左節點
root.left = helper(root.right);
root.right = helper(mid);
return root;
}
}
這個非常善用遞歸,在對樹(指針實現)進行編程的時候,因爲層層往下的結構都是一樣的,所以遞歸在裏面就非常地好用。
答案二是參考一個大佬,分別前中後和層次遍歷來解答這題,不使用遞歸。
核心代碼:
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
前序遍歷非遞歸
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null){
return null;
}
TreeNode node = root;
Deque<TreeNode> stack = new LinkedList<>();
while (node != null || !stack.isEmpty()){
if (node != null){
// 交換左右子樹
inventTreeNode(node);
// 原先的先序遍歷
stack.push(node);
node = node.left;
}else {
node = stack.pop();
node = node.right;
}
}
return root;
}
private void inventTreeNode(TreeNode node){
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
}
這裏的Deque是雙向隊列,可以直接實現Stack和Queue兩種數據結構的功能。具體看下面這個網址:
https://blog.csdn.net/u013967628/article/details/85210036
中序遍歷非遞歸
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null){
return null;
}
TreeNode node = root;
Deque<TreeNode> stack = new LinkedList<>();
while (node != null || !stack.isEmpty()){
if (node != null){
stack.push(node);
node = node.left;
}else {
node = stack.pop();
// 交換左右子樹
inventTreeNode(node);
// 這裏因爲交換了,不能繼續往右子樹走,因爲現在的右子樹,是原來的左子樹
// 所以接下來要走左邊
node = node.left;
}
}
return root;
}
private void inventTreeNode(TreeNode node){
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
}
後序遍歷非遞歸
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null){
return null;
}
TreeNode node = root;
TreeNode tempNode = null;// 記錄上次訪問的節點
Deque<TreeNode> stack = new LinkedList<>();
while (node != null || !stack.isEmpty()){
if (node != null){
stack.push(node);
node = node.left;
} else {
node = stack.peek();
if (node.right == null || node.right == tempNode){
// 右節點爲空,或者右節點已經被訪問過
// 當前節點出棧
tempNode = stack.pop();
// 交換
inventTreeNode(node);
// 這裏要置空,不然node還是存在,又會往左子樹去了
node = null;
}else {
node = node.right;
}
}
}
return root;
}
private void inventTreeNode(TreeNode node){
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
}
層次遍歷非遞歸
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode node = root;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(node);
while(!queue.isEmpty()){
node = queue.poll();
// 翻轉左右子樹
inventTreeNode(node);
if(node.left != null){
queue.offer(node.left);
}
if(node.right != null){
queue.offer(node.right);
}
}
return root;
}
private void inventTreeNode(TreeNode node){
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
}
6.
方法一:使用雙指針來解決這個問題。解題思路看下圖:
申請兩個指針,第一個指針叫 pre,最初是指向 null 的。
第二個指針 cur 指向 head,然後不斷遍歷 cur。
每次迭代到 cur,都將 cur 的 next 指向 pre,然後 pre 和 cur 前進一位。
都迭代完了(cur 變成 null 了),pre 就是最後一個節點了。
代碼如下:
class Solution {
public ListNode reverseList(ListNode head) {
//申請節點,pre和 cur,pre指向null
ListNode pre = null;
ListNode cur = head;
ListNode tmp = null;
while(cur!=null) {
//記錄當前節點的下一個節點
tmp = cur.next;
//然後將當前節點指向pre
cur.next = pre;
//pre和cur節點都前進一位
pre = cur;
cur = tmp;
}
return pre;
}
}
方法二:使用遞歸,遞歸理解確實非常困難
三個問題:1.這個函數是用來解決什麼的 2.遞歸調用的結束條件是什麼 3.尋求一個等式關係
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
//遞歸終止條件是當前爲空,或者下一個節點爲空
if(head==null || head.next==null) {
return head;
}
//這裏的cur就是最後一個節點
ListNode cur = reverseList(head.next);
//這裏請配合動畫演示理解
//如果鏈表是 1->2->3->4->5,那麼此時的cur就是5
//而head是4,head的下一個是5,下下一個是空
//所以head.next.next 就是5->4
head.next.next = head;
//防止鏈表循環,需要將head.next設置爲空
head.next = null;
//每層遞歸函數都返回cur,也就是最後一個節點
return cur;
}
}
7.
我的解法:2 ms
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
Deque<Integer> stack = new LinkedList<>();
while(head != null){
stack.push(head.val);
head = head.next;
}
int [] outer = new int[stack.size()];
int i =0;
while(!stack.isEmpty()){
outer[i++] = stack.pop();
}
return outer;
}
}
我這個方法簡單明瞭,先弄一個棧,利用棧先入後出的特點,將一個一個節點的數值壓棧,然後再將棧裏的值一一出棧就是我們所需要的數組。但這裏需要兩個循環,因爲首先要入棧然後再出棧。
方法二:一個大神的答案,使用的遞歸 1ms
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
ArrayList <Integer> arrays = new ArrayList<>();
public int[] reversePrint(ListNode head) {
//遞歸的結束條件:head == null
recur(head);
int [] outer = new int[arrays.size()];
for(int i=0;i<outer.length;i++){
outer[i] = arrays.get(i);
}
return outer;
}
public void recur(ListNode head){
if(head == null){
return;
}
recur(head.next);
arrays.add(head.val);
}
}
將head.next編程遞推函數的參數,定位到鏈表最後一位。所以這裏arrays.add(head.val)添加順序並不是從頭到尾,而是從尾到頭。添加完畢後只需要將其輸出就行。
這裏當時還發生了一個錯誤,我沒有將ArrayList <Integer> arrays = new ArrayList<>();這一行寫到reversePrint方法外,想想爲什麼不這麼做就報錯?報錯行是arrays.add(head.val);
8.
做了半天,沒做出來。貼出別人的解法
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dum = new ListNode(0), cur = dum;
while(l1 !=null &&l2 !=null){
if(l1.val >= l2.val){
cur.next = l2;
l2=l2.next;
cur = cur.next;
}else{
cur.next = l1;
l1=l1.next;
cur = cur.next;
}
}
if(l1 !=null){
cur.next = l1;
}else{
cur.next = l2;
}
return dum.next;
}
}
看了大佬思路,我完成的代碼,思路如下:
這裏我有2個問題,值得以後反覆琢磨:
1.爲什麼return dum.next;就可以把整條鏈條都給返回?
2.僞頭結點的意義?
9.
class CQueue {
Deque<Integer> stack1,stack2;
public CQueue() {
stack1 = new LinkedList<Integer>();
stack2 = new LinkedList<Integer>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if(!stack2.isEmpty()){
return stack2.pop();
}else if (!stack1.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}else{
return -1;
}
}
}
解題思路:簡而言之就是stack2作爲改變stack1順序的一個工具,因爲比如輸入123,stack1裏面就是321,這時候輸出肯定是不對的,這就不是隊列了,所以需要Stack2來倒序,繼續變成123,這時候再輸出就行。
10.
解法一:主要思路就是用位運算,n&1,相當於n的最右邊一位和1做位運算,當然如果最右邊一位是1,得到1反之則爲0 .
然後需要將n右移,Java中有兩個右移“>>”(有符號)和“>>>”(無符號)兩種。
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count = 0;
while(n != 0){
int tmp = n & 1;
if(tmp == 1){
count++;
}
n >>>= 1;
}
return count;
}
}
解法二:一個大佬的思路非常巧妙
public class Solution {
public int hammingWeight(int n) {
int res = 0;
while(n != 0) {
res++;
n &= n - 1;
}
return res;
}
}
思路如下: