算法练习(1)-字符串/单链表反转

前提:不能借助其它数据结构或一些现成工具类。比如调用StringUtils.reverse(str)完成翻转,或者先入stack再出stack。仅使用最基本的分支/循环来实现最优解法。

一、字符串反转

java中字符串,其实就是一个字符数组,可以用数组的思路,首尾交换即可。

    private String reverseString(String str) {
        char[] arr = str.toCharArray();
        for (int i = 0; i < arr.length / 2; i++) {
            int j = arr.length - i - 1;
            char temp = arr[j];
            arr[j] = arr[i];
            arr[i] = temp;
        }
        return new String(arr);
    }

 

二、单链表反转

2.1 头插法

单链表只能从头节点开始1个个向后查找。这里有一个小技巧:通常会在头部加一个节点,不存放任何数据,只是为了方便快速找到头节点。

单链表的测试类如下:

    class LinkNode {
        public String value;
        public LinkNode next;

        public LinkNode(String v, LinkNode next) {
            this.value = v;
            this.next = next;
        }
    }

    LinkNode buildTestLinkNode() {
        LinkNode d = new LinkNode("d", null);
        LinkNode c = new LinkNode("c", d);
        LinkNode b = new LinkNode("b", c);
        LinkNode a = new LinkNode("a", b);
        LinkNode dummy = new LinkNode("dummy", a);
        return dummy;
    }

    void printLinkNode(LinkNode head) {
        while (head.next != null) {
            System.out.print(head.value + "->");
            head = head.next;
        }
        System.out.print(head.value + "\n");
    }

    @Test
    public void testPrintLinkNode() {
        printLinkNode(buildTestLinkNode());
    }

打印出来为:dummy->a->b->c->d

反转的思路如下:

从第2个有效节点开始,将其从链表中摘下来,然后放到哑节点后面,不断重复这个过程。

    @Test
    public void testReverseLinkNode() {
        LinkNode dummy = buildTestLinkNode();
        printLinkNode(dummy);
        reverseLinkNode(dummy);
    }

    /**
     * 单链表反转
     * @param dummy
     */
    private void reverseLinkNode(LinkNode dummy) {
        if (dummy == null || dummy.next == null || dummy.next.next == null) {
            return;
        }
        LinkNode prev = dummy.next;
        LinkNode curr = prev.next;
        while (true) {
            prev.next = curr.next;
            curr.next = dummy.next;
            dummy.next = curr;
            curr = prev.next;
            printLinkNode(dummy);
            if (curr == null) {
                break;
            }
        }
    }

输出结果:

dummy->a->b->c->d
dummy->b->a->c->d
dummy->c->b->a->d
dummy->d->c->b->a

 

2.2 原地翻转

LinkNode prev = null, curr = head, next;
while (curr != null) {
    next = curr.next;
    curr.next = prev;
    prev = curr;
    curr = next;
}
return prev;

过程就不画了, 建议感兴趣的同学自己在纸上画一画。

 

2.3 递归法

static LinkNode reverse3(LinkNode curr) {
    if (curr == null || curr.next == null) {
        return curr;
    }
    //递归调用时,会不停压栈,直到最后节点,然后再一层层返回
    //所以使用递归方式,效果上相当于1个个node放到stack,再弹出来
    reverse3(curr);
    curr.next.next = curr;
    curr.next = null;
    return curr;
}

注:递归法,本质上跟自己弄一个stack,将链表元素1个个压入,再1个个弹出是等效的,只不过递归过程,系统自动会帮我们压栈、出栈。

posted @ 2020-06-24 16:07  菩提树下的杨过  阅读(516)  评论(0编辑  收藏  举报