算法日记 second

Example 1:

Input: "()"
Output: true

Example 2:

Input: "()[]{}"
Output: true

Example 3:

Input: "(]"
Output: false

Example 4:

Input: "([)]"
Output: false

Example 5:

Input: "{[]}"
Output: true
class Solution {
    public boolean isValid(String s) {
        
        boolean flag=true;
        if ((s.length() & 1) == 1)
            return false;
        Stack<Character> sta=new Stack<Character>();
        for(char ch:s.toCharArray()){
            
            if(ch=='('){
                sta.push(')');
            }
            else if(ch=='['){
                sta.push(']');
            }
            
            else if(ch=='{'){
                sta.push('}');
            }
            
           else if (sta.isEmpty() || sta.pop() != ch){
                return false;
           }
        }
        return sta.isEmpty();
    }
}

JAVA 堆栈类(Stack)的使用

堆栈是一种 “后进先出”  (LIFO) 的数据结构, 只能在一端进行插入(称为 “压栈” ) 或删除 (称为“出栈”)数据的操作。

JAVA 中,使用 java.util.Stack 类的构造方法创建对象。

 public class Stack extends vector

 构造方法 : public Stack() 创建一个空 Stack。

方法:  1. public push  (item )  把项 压入栈顶。其作用与 addElement (item ) 相同。

      参数 item 压入栈顶的项 。 返回: item 参数 ;

    2. public pop () 移除栈顶对象,并作为函数的值 返回该对象。

      返回:栈顶对象(Vector 对象的中的最后一项)。

      抛出异常 : EmptyStackException 如果堆栈式空的 。。。

    3. public peek() 查看栈顶对象而不移除它。。 

      返回:栈顶对象(Vector 对象的中的最后一项)。

      抛出异常 : EmptyStackException 如果堆栈式空的 。。。

    4. public boolean empty (测试堆栈是否为空。)  当且仅当堆栈中不含任何项时 返回 true,否则 返回 false.

    5. public int search  (object o)  返回对象在堆栈中位置, 以 1 为基数, 如果对象 o是栈中的一项,该方法返回距离 栈顶最近的出现位置到栈顶的距离; 栈中最上端项的距离

        为 1 。 使用equals 方法比较 o 与 堆栈中的项。。。   

      参数: o 目标对象;

A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.

Example:

Input: "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
class Solution {
    public List<String> letterCombinations(String digits) {
      HashMap<Integer, String[]> hashmap=new HashMap<>();
       hashmap.put(2,new String[]{"a","b","c"});
       hashmap.put(3,new String[]{"d","e","f"});
       hashmap.put(4,new String[]{"g","h","i"});
       hashmap.put(5,new String[]{"j","k","l"});
       hashmap.put(6,new String[]{"m","n","o"});
       hashmap.put(7,new String[]{"p","q","r","s"});
       hashmap.put(8,new String[]{"t","u","v"});
       hashmap.put(9,new String[]{"w","x","y","z"});
        int len=digits.length();
		 List<String> res=new ArrayList<>();
		 for(int i=0;i<len;i++) {
			 int flag=Integer.parseInt(digits.substring(i, i+1));
			 String[] tmp=hashmap.get(flag);
			 List<String> list_tmp=new ArrayList<>();
             if(i!=0){
                 for(int j=0;j<res.size();j++){
                     for(int k=0;k<tmp.length;k++){
                     list_tmp.add(res.get(j)+tmp[k]);
                         }
                 }
                 res=list_tmp;
             }else{
                     for(int k=0;k<tmp.length;k++){
                         res.add(tmp[k]);
                     }
                 }
			 
                 
             
		 }
	     return res;
    }
}

链表的基础知识以及题目

单向链表的产生以及遍历;

public class Node{
        int data;
        Node next;        

        public Node(object data){
            
            this.data=data;
        }
}

public class LinkList{

        Node head;
        Node current;
       //添加元素
        public void add(Object data){
            if(head==null){
                head=new Node(data);
                current=head;
            }else{
                current.next=new Node(data);
                current=current.next;
            }
        
        }//从这个部分开始遍历
        public void print(Node node){
            current=node;
            if(current==null) return ;
            while(current!=null){

                System.out.println(current);
                current=current.next;
            }

        }
        //测试部分
        public static void main(String [] args){
            LinkList linklist=new LinkList();
            for(int i=0; i<10;i++){
                linklist.add(i);
            }
            linklist.print(list.head);
        }
}

2求单向链表中节点的个数(要给出节点的起点,要是长度的话必然是头结点)

public int getLength(Node head){

        int length=0;
        if(head==null) return length;
        current=head;
        while(current!=null){
            length++;
            current=current.next;
        }
        return length;
}

3查找倒数第K个节点

//允许遍历得到长度的情况下
public int getLastNode(int index){
      
        if(head==null) return ;
        current=head;
        int length=0;
        while(current!=null){
            current=current.next;
            length++;
        }
        current=head;
        for(int i=0;i<length-index+1;i++){
                current=current.next;
            }
        return current.data;
}

//要是不允许遍历得到链表的长度
public int getLastNode(Node head,int index){
      //Node head 给出要给的头结点
        if(head==null) return ;
        Node current2=head;
        for(int i=0;i<index-1;i++){
                current1=current1.next;
                while(curent==null) return ;
            }
        Node current1=head;
        while(curent2!=null){
            current1=current1.next;    
            xurrent2=current2.next;
        }
        return current1.data;
}

4查找出中间节点,不允许遍历链表

public Node getMiddleNode(Node head){

      if(head==null) return null;
      Node first=head;
      Node second=head;
      while(second!=null&&second.next!=null){
        first=first.next;
        second=second.next.next;
        }

    return first;
}

5合并两个有序单向链表,合并之后仍然有序

public Node mergeLinkList(Node node1,Node node){

        Node current;
        Node head;
        if(node1==null&&node2==null) return null;
        if(node1==null) return node2;
        if(node2==null) return node1;
        if(node1.data>node2.data){
            head=node1;
            node1=node1.next;
            current=head;
            current=current.next;
        }else{
            head=node2;
            node2=node2.next;
            current=head;
            current=current.next;
            
        }
        while(node1!=null&&node2!=null){
            if(node1.data>node2.data){
                current=node1;
                node1.next;
                current=current.next;
            }else{
                current=node2;
                node2.next;
                current=current.next;
            }

        }
        while(node1!=null){
                current=node1;
             //赋值的时候不用遍历
        }
        while(node2!=null){
                current=node2;
        }
        return current;
 }

6单链表的反转

public Node reverseNode(Node head){

        if(head==null||head.next==null) return head;
        Node newNode;
        Node temp;
        Node current;
        current=head;
        while(current!=null){
            temp=current
            current.next=newNode;
            newNode=current;
            current=temp.next;

        }
return newNode;
}

7从尾到头打印单向链表

public void printReverse(Node head){

       Node current;
       Node head;
       if(head==null) return head;
       current=head;
       Stack<Node> stack=new Stack <Node>();
       while(current!=null){
            stack.push(current);
            current=current.next;
        }
       while(!stack.isEmpty){
            System.out.println(stack.pop());
        }

}

8判断单链表是否有环

public boolean isCycle(Node head){

        if(head==null||head.next==null) return false;
        Node first=head;
        Node second=second;
        boolean flag=false;
        while(second!=null){
            first=first.next;
            second=second.next.next;
            if(first==second){
                flag=true;
            }
        }
        return flag;
}

9取出有环链表的长度;

public int getCycleLength(Node head){
        int length=0;
        if(head==null||head.next=null) return length;
        Node first=head;
        Node second=head;
        Node node;
        while(second!=null){
            first=first.next;
            second=second.next.next;
            if(first==second) node=first;
        }
        //node再次走到node才是环的长度,因为会一直走下去;
        Node current=node;
        while(current!=null){
            length++;
            if(current==node) return length;
            node=node.next;
        }

        return length;
}

10判断两个单向链表首次相交的节点位置,Y型链表,这个我面试的时候真的遇到过!!!!!

public Node getCommonNode(Node first,Node second){
        
        if(frist==null||second==null) return null;
        Node longerNode;
        Node smallerNode;
        int longerlength=0;
        if(getLength(first)>getLength(second)){
            longerNode=first;
            smallerNode=second;
            longerLength=getLength(first)-getLength(second);
        }else{
            longerNode=second;
            smallerNode=first;
            longerLength=getLength(second)-getLength(first);
        }
        for(int i;i<longerLength;i++){
            longerNode=longerNode.next;
        }
        while(longerNode!=null&&smallerNode!=null){
            if(longerNode==smallerNode) return longerNode;
            longerNode++;
            smallerNode++;
        }
        return null;
}
public int getLength(Node head){
      if(head==null) return 0;
      Node current=head;
      int length=0;
      while(current!=null){
        length++;
        current=current.next;
        }
    return length;
}

在单链表中,我们只能从头结点开始顺序遍历,最后才能到达尾结点。最后到达的尾节点却要先被比较,这听起来是不是像“先进后出”?于是我们就能想到利用栈的特点来解决这个问题:分别把两个链表的结点放入两个栈中,这样两个链表的尾结点就位于两个栈的栈顶,接下来比较下一个栈顶,直到找到最后一个相同的结点

首先遍历两个链表得到它们的长度。在第二次遍历的时候,在较长的链表上走 |len1-len2| 步,接着再同时在两个链表上遍历,找到的第一个相同的结点就是它们的第一个交点

这种思路的时间复杂度也是O(len1+len2),但是我们不再需要辅助栈,因此提高了空间效率。

这种思路中,我们需要利用两个辅助栈,空间复杂度是O(len1+len2),时间复杂度是O(len1+len2)。和一开始的蛮力法相比,时间效率得到了提高,相当于是利用空间消耗换取时间效率

leetcode18 4数之和

Given array nums = [1, 0, -1, 0, -2, 2], and target = 0. A solution set is: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]

class Solution {//回溯??估计是了,先把循环做了
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        if (nums == null || nums.length < 4) {
            return res;
        }
        
        Arrays.sort(nums);
        for (int i = 0; i < nums.length - 3; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            
            int sum3 = target - nums[i];  // 后3个数之和需等于sum3
            for (int j = i + 1; j < nums.length - 2; j++) {//j=i+1一直写成1+1,找了和我写的差不多的博客粘过去就是对的,我也不知道为啥,就瞅啊瞅,嗯。。。没毛病
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                
                int sum2 = sum3 - nums[j];  // 后2个数之和需等于sum3
                int left = j + 1, right = nums.length - 1;
                
                while (left < right) {
                    if (nums[left] + nums[right] == sum2) {
                        List<Integer> quad = new ArrayList<>();
                        quad.add(nums[i]);
                        quad.add(nums[j]);
                        quad.add(nums[left]);
                        quad.add(nums[right]);
                        res.add(quad);
                        
                        while (left < right && nums[left++] == nums[left]) {}
                        while (left < right && nums[right--] == nums[right]) {}
                        
                    } else if (nums[left] + nums[right] < sum2) {
                        while (left < right && nums[left++] == nums[left]) {}
                        
                    } else {
                        while (left < right && nums[right--] == nums[right]) {}
                    }
                }
            }
        }
        return res;
    }
}

 

为什么不是全部寻找呢????因为有点多余.每个都不同,必然是取一个少一个...取全部长度也是可以的..

leetcode22

For example, given n = 3, a solution set is:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]
class Solution {//随机生成还是其他别的什么
    public List<String> generateParenthesis(int n) {
       
        List<String> res=Arraylist<String>();
        String str=new String();
        generator(res,str,n,n);
        return res;
       
    }
    public void generator(List<String> list,String str,int left,int right){
        
            if(left==0&&right==0){
                list.add(str);
                return ;
            }
            if(left>0){
                generator(list,str+"(",left-1,right);
            }
            if(left<right){
                generator(list,str+")",left,right-1);
            }
        }
}
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
/**
 * 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 head=new ListNode(0);
        ListNode current=head;//虚假的头结点,真正的头结点是current.next
        if(l1==null&&l2==null) return null;
        if(l1==null) return l2;
        if(l2==null) return l1;
        while(l1!=null||l2!=null){
        if(l1==null){
            current.next=l2;
            break;
        }
        if(l2==null){
            current.next=l1;
            break;
        }
        if(l1.val>l2.val){
                current.next=l2;
                l2=l2.next;
        }else{
              current.next=l1;
              l1=l1.next;
            }
            
            current=current.next;
        }
        
       return current; 
    }
}

解答部分来自于:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

    ListNode *reverseBetween(ListNode *head, int m,int n){
        ListNode dummy(-1);//定义一个假的节点,不是指针,是一个局部变量。
        dummy.next = head;//成为新的头节点,这样真链表的头节点就是dummy.next
               //这时候,我们的head节点也有prev指针了,head和其他节点在前驱指针这一方面,就没有区别了。
        ListNode *prev = &dummy;
        for(int i = 0;i<m-1;i++){//我们的prev应该指向的是,第m个节点的前驱节点
            prev = prev->next;
        }//跳出循环后我们的prev就是指向第m个节点前驱节点

        ListNode *const head2 = prev;///把这个前驱节点 记做head2,因为后面要采用头插法的方式来build 链表,什么是头插法,什么是尾插法,这个一定要弄清楚了。

        prev = head2->next;///prev现在指的是第m个节点,
        ListNode *curr = prev->next;///curr指向prev的下一个节点
        for(int i = m;i<n;i++){///对于每一个i (m<i<=n)的节点,利用头插法插入到head2所在的链表中。

          [===]  ...  [===]  [===]  [===]
          head2         prev   curr   

            prev->next = curr->next;///这一步之后curr就独立了
            curr->next = head2->next;///1
            head2->next = curr;///2  这一步和上一步就是头插法了
            curr = prev->next;curr指针后移一个位置
        }

        return dummy.next;
    }

leetcode29

Example 1:

Input: dividend = 10, divisor = 3
Output: 3

Example 2:

Input: dividend = 7, divisor = -3
Output: -2

做除法,要求不使用乘法,除法和mod运算符。返回dividend除以除数divisior的商

class Solution {
    public int divide(int dividend, int divisor) {
             if(dividend==Integer.MIN_VALUE&&divisor==-1) return Integer.MAX_VALUE;
     if(dividend==0) return 0;
     if(divisor==1) return dividend;
    long a=Math.abs((long)dividend);
    long b=Math.abs((long)divisor);
    int num=0;
    long sum=0;
    while(b<=a){
        int count=1;
        sum=b;
        while(sum+sum<=a){
            count+=count;
            sum+=sum;
        }
        a=a-sum;
        num=count+num;
        }
    if((dividend>0&&divisor<0)||(dividend<0&&divisor>0)){
        num=-num;
    }
    if(num>Integer.MAX_VALUE) return Integer.MAX_VALUE;
    return num;
    }

}

Example:

Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6    //我猜用递归
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {//为什么会超时
    public ListNode mergeKLists(ListNode[] lists) {
      if(lists==null||lists.length==0) return null;
      int begin=0;
      int end=lists.length-1;
      while(begin<end){
        int mid=(end+begin-1)/2;
            for(int i=0;i<=mid;i++){
             lists[i]=merge2list(lists[i],lists[end-i]);   
            }
         end=(end+begin)/2;
        }
     return lists[0];
    }
    public ListNode merge2list(ListNode l1,ListNode l2){
        if(l1==null&&l2==null) return null;
        if(l1==null) return l2;
        if(l2==null) return l1;
        ListNode head=new ListNode(0);
        ListNode current=head;
        while(l1!=null&&l2!=null){
            if(l1.val>l2.val){
                current.next=l1;
                l1=l1.next;
             }else{
                current.next=l2;
                l2=l2.next;
             }
            current=current.next;
        }
        while(l1==null){
            current.next=l2;
            //l2=l2.next;
            //current=current.next;
        }
        while(l2==null){
            current.next=l1;
            //l1=l1.next;
            //current=current.next;
        }
    return head.next;
    }
}
class Solution {
     public ListNode mergeKLists(ListNode[] lists) {
    if (lists == null || lists.length == 0) return null;
        int begin = 0, end = lists.length - 1;
        while (begin < end) {
            int mid = (begin + end - 1) / 2;
            for (int i = 0; i <= mid; i++) {
                lists[i] = merge2list(lists[i], lists[end - i]);
            }
            end = (begin + end) / 2;
        }
        return lists[0];
    }
    public ListNode merge2list(ListNode l1, ListNode l2) {
        if (l1 == null && l2 == null) return null;
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        ListNode dummy = new ListNode(-1), cur = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                cur.next = l1;
                cur = l1;
                l1 = l1.next;
            } else {
                cur.next = l2;
                cur = l2;
                l2 = l2.next;
            }
        }
        if (l1 != null) cur.next = l1;
        if (l2 != null) cur.next = l2;
        return dummy.next;

    }
}
class Solution {
     public ListNode mergeKLists(ListNode[] lists) {
    if(lists.length==0)
            return null;
        return merge(0,lists.length-1,lists);
    }
    public ListNode merge(int i,int j,ListNode[] lists) {
        if(j<i)return null;
        if(i==j)return lists[i];
        int mid=i+(j-i)/2;
        ListNode l=merge(i,mid,lists);
        ListNode r= merge(mid+1,j,lists);
        ListNode dummy =new ListNode(0);
        ListNode runner= dummy;
 
        while(l!=null && r!=null) {
            if(l.val>r.val) {
                runner.next=r;
                r=r.next;
                runner=runner.next;
            }
            else {
                runner.next=l;
                l=l.next;
                runner=runner.next;
            }
        }
        if(l==null && r==null)
            return dummy.next;
        if(l==null)
            runner.next=r;
        else
            runner.next=l;
        return dummy.next;

    }
}

归并排序:将其分成两本份,分别排序好后,合并好再排序,需要额外的空间

快速排序:将其分成两部份(不一定相等),分别排序,不需要额外的空间。。

public Sort{

  begin=0;
  end=length-1;
  mid=begin+end-1/2;
  sort(begin,mid);
  sort(mid+1,end);
}

leetcode 26

class Solution {
    public int removeDuplicates(int[] nums) {
        int num=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=nums[num]){
                num++;
                nums[num]=nums[i];
                
            }
        }
       num+=1;
       return num;
    }
}
leetcode 21 下一个全排列,题目都没看懂的我真是个智障

 

就是将这个数组排列成下一个较大的数,如果已经是最大的了,就排列成最小的数。

我是这么想的,从后往前遍历数组,如果一直是逐渐增大的,则已经是最大的了,如果出现了一个下降的数,那么遍历就到此为止,因为这已遍历的部分就可以排列成下一个较大的数了

当找到这个突然下降的点A后,由于它后面已经排列为“最大”,即从前往后一直变小,所以应该从后面比A大的数中找最小的点B,然后A和B交换位置。这个时候以B开头,后面也是最大的排列,由于需要找下一个较大的数,应该把B后面的排列改为最小的,只需要将后面的数组顺序逆转一下即可。如果一直没有找到下降的点,则全部逆转即可。
 

class Solution {
    public void nextPermutation(int[] nums) {
                if(nums==null&&nums.length==0) return ;       
           //如果是逆序那么直接把它顺过来就好,其他是颠倒两个元素的问题。
            int i=0;
           int len=nums.length;
           for(i=len-1;i>0;i--){
                if(nums[i-1]<nums[i]){
                    continue;
                    }else{
                      for(int j=len-1;j>=i;j--){
                        if(nums[i-1]>=nums[j]){
                            continue;
                            }else{
                            int a=nums[i-1];
                            nums[i-1]=nums[j];
                            nums[j]=a;
                            }
                         break;    
                        }
                    break;
                    }
            
            }

            swap(nums,i,len-1);
        }
        public void  swap(int[] nums,int left,int right){
            while(left<right){
              int temp=nums[right];
              nums[right]=nums[left];
              nums[left]=temp;
              left++;
              right--;  
                }
        }

}


leetcode33 搜索旋转排序数组

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

二分法:

class Solution {
    public int search(int[] nums, int target) {
        int ret=-1;
        if(nums.length==0) return ret;
        int begin=0;
        int end=nums.length-1;
        int mid=0;
        while(begin<=end){
            mid=begin+(end-begin)/2;
            if(nums[begin]<nums[mid]){
                if(nums[begin]==target){
                    return begin;
                    }else if(nums[mid]==target){
                    return mid;
                    }else if(nums[begin]<target&&nums[mid]>target){
                           end=mid-1;
                    }else {
                           begin=mid+1;
                    }
            }else{
                if(nums[end]==target){
                    return end;
                    }else if(nums[mid]==target){
                    return mid;
                    }else if(nums[mid]<target&&nums[end]>target){
                           begin=mid+1;
                           
                    }else {
                           end=mid-1;
                    }
            }//else
        }//while
   return ret;
    
    }  
    
}

 

leetcode 34 find first and last index of the target

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
class Solution {
    public int[] searchRange(int[] nums, int target) {
        //必然是二分法,但是第一个和最后一个index
         int left=0;
        int right=nums.length;
        int mid=(left+right)/2;
        int p=-1;
        while(left<right){
            if(nums[mid]==target){
                p= mid;
                break;
            }else if(nums[mid]<target){
                if(left==mid) break;
                left=mid;
                mid=(right+left)/2;
            }else if(nums[mid]>target){
                if(mid==right) break;
                right=mid;
                mid=(right+left)/2;
            }
         }
       if(p==-1){
         return new int[]{-1, -1};
       }else{
         int a=p,b=p;
         while(a>0&&nums[a-1]==target){ a--;}
         while(b<nums.length&&nums[b+1]==target){ b++;}
         return new int[]{a,b};
       }
    }
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值