我的解法如下:
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;
}
}
思路如下: